/**************************************************************************************
****************************  SUBSPACE ASTEROIDS  V1.01 *******************************
***************************************  by  ******************************************
*************************  Kevin Jenkins (kevin@mpog.com) *****************************
***************************************************************************************
*                                                                                     *
*  I wrote this because I've always loved the ships in Subspace and thought it would  *
*  be cool to play them in Asteroids.  I asked around but nobody with any Asteroids-  *
*  style game was willing to take friggin' 5 minutes to implement reverse thrust.     *
*  Well, if you want a job done right do it yourself.  It took me a week to write     *
*  this and I did my best to copy the original and supreme Subspace ship settings.    *
*  You may have noticed the ships and settings come out of Subspace.  Most of the     *
*  DirectX wrapper functions are from the book Windows Game Programming for Dummies.  *
*  This is freeware so feel free to distribute or modify the code as you wish.  If    *
*  you copy my code directly though please give credit where credit is due :)         *
*                                                                                     *
***************************************************************************************
*****************************  Written October of 1999  *******************************
**************************************************************************************/

#define WIN32_LEAN_AND_MEAN

#include <windows.h>   // include important windows stuff
#include <windowsx.h>
#include <dos.h>
#include "gpdumb2.cpp"
#include "gpdumb1.cpp"

// DEFINES ////////////////////////////////////////////////

// XY Coordinate AXIS defines
// These set the maximum +- boundaries of the rectangular subspace in pixels before an object scrolls.
// Higher values will cause asteroids to be farther apart.  DO NOT SET BELOW 1/2 MAX RESOLUTION (800).
#define MAXX 1000
#define MAXY 1000

#define MAX_BIG_ROCKS 64  // Maximum number of big rocks allowed due to static memory allocation
#define MAX_MEDIUM_ROCKS 128  // Maximum number of medium rocks allowed due to static memory allocation
#define MAX_SMALL_ROCKS 256  // Maximum number of small rocks allowed due to static memory allocation
#define BIG_ROCK_SIZE 64  // X and Y dimensions of the big rock.  The rock must be square
#define MEDIUM_ROCK_SIZE 32  // X and Y dimensions of the medium rock.  The rock must be square
#define SMALL_ROCK_SIZE 16  // X and Y dimensions of the small rock.  The rock must be square
#define ROCK_HP_RANGE .20 // + or - up to this percent off max hp for each rock
#define BOMB_DAMAGE_RANGE .20 // + or - up to this percent off damage  for each bomb
#define BULLET_DAMAGE_RANGE .20  // + or - up to this percent off damage  for each bullet
#define MAXSPEED 9.1  // Maximum magnitude of velocity vectors.  3.7 seconds to go 1200 pixels in SS
#define ACCELERATION .13  // Acceleration per 1 time delay using GetTickCount()
#define ACCELERATION_RATE 11 // Time in ms before ship is accelerated 1 ACCELERATION unit
#define ROCK_RATE 25 // Time in ms before rock positions are updated
#define GAME_RATE 33  // Higher values make wb turn slower and framerate decrease but run smoother on slower computers
#define MAX_STARS 160 // Maximum number of stars to display
#define PARALLAX_RATE 10.0 // Higher makes stars in background move more slowly.  Set to 1 and stars move at 1:1
#define EXHAUST_BMP_FRAMES 19 // Number of frames in exhaust bmp file.
#define BULLET_BMP_FRAMES 4  // Number of frames in bullet bmp file.
#define BULLET_FLASH_BMP_FRAMES 6 // Number of frames in bulletfl bmp file
#define DAMAGE_BMP_FRAMES 26 // Number of frames in damage bmp file
#define BOMB_BMP_FRAMES 10 // Number of frames in bomb bmp file
#define EXPLODE1_BMP_FRAMES 34 // Number of frames in explode1 bmp file
#define EXPLODE2_BMP_FRAMES 44 // Number of frames in explode2 bmp file
#define SHIELD_BMP_FRAMES 10 // Note this is used for both ssshield and shield bmp files since they have the same number of frames
#define WARP_BMP_FRAMES 16  // Number of frames in warp bmp file
#define ENERGY_BAR_DOWNSET 10 // How many pixels from the top of the screen to put the energy bar thing
#define BULLET_COST 45 // Energy cost to shoot a bullet
#define BOMB_COST 340 // Energy cost to shoot a bomb
#define BOMB_ITERATION 45  // Number of loops main game loop must repeat before you can shoot another bomb
#define BULLET_ITERATION 8  // Number of loops main game loop must repeat before you can shoot another bullet
#define MAX_BULLETS 23 // Maximum number of bullets allowed at one time
#define MAX_BOMBS 10 // Maximum number of bombs allowed at one time
#define BULLET_LIFETIME 200 // How many main game loops bullet will last before a decay
#define BULLET_SPEED 6 // More or less vectors per turn, but adjusted to angle  Should take 2.90 seconds to go 1200 pixels
#define BOMB_SPEED 6 // Should take 3.8 seconds to go 1200 pixels
#define BOMB_LIFETIME 200  // How many main loops will pass before bomb decays
#define RADAR_SIZE 200.0  // How many pixels wide,tall the radar is
#define SMALL_ROCK_RADAR_COLOR 134  // Palette number used for the color of the small rock on the radar
#define MEDIUM_ROCK_RADAR_COLOR 169  // Palette number used for the color of the medium rock on the radar
#define BIG_ROCK_RADAR_COLOR 46  // Palette number used for the color of the big rock on the radar
#define SHIP_RADAR_COLOR 109  // Palette number used for the color of your ship on the radar
#define RECOIL_STRENGTH 11 // Amounts to holding down the back arrow key that many main game loops
#define BULLET_DAMAGE 330  // Damage done by your bullets
#define BOMB_DAMAGE 950  // Maximum damage done by your bombs.  Officially it's 730 but for gameplay reasons I raised it
#define SMALL_ROCK_MASS 100.0  //  Mass of the small rocks used in determining collisions
#define MEDIUM_ROCK_MASS 800.0  //  Mass of the medium rocks used in determining collisions
#define BIG_ROCK_MASS 2700.0  //  Mass of the big rocks used in determining collisions
#define LOWER_PALETTE_BULLET_COLOR 207  // Bullet color increases from the lower palette bullet color to the upper.and then starts at lower again
#define UPPER_PALETTE_BULLET_COLOR 219
#define MAX_EXPLODE2 3 // How many of these big explosions can exist at one time.
#define DEAD_DELAY 50 // How many main game loops that will pass before it attemps to respawn you
#define LAMER 0  // Just a tag for the skill level variable
#define DUELER 1
#define HUNTER 2
#define RAKKAR 3
#define SHIELD_LIVES 5 // Number of lives represented by the yellow shield (shield1)
#define SHIELDY 56 // Number of pixels from top of screen to draw center of shields which indicate lives
#define SHIELD_ANIM_SPEED 3 // Higher this number is the slower the shields will rotate
#define MAX_EXPLOSION_SOUNDS 10 // Maximum number of explosion sounds that can be played at once.
#define SCORE_MULTIPLIER_640X480 4.0  //  Multipliers applied to score at various resolutions
#define SCORE_MULTIPLIER_800x600 2.5
#define SCORE_MULTIPLIER_1024x768 1.5
#define SCORE_MULTIPLIER_1280x1024 1.2
#define SCORE_MULTIPLIER_1600x1200 1.0
#define SCORE_MULTIPLIER_LAMER 1.0  // Multipliers applied to score at various difficulties
#define SCORE_MULTIPLIER_DUELER 3.0
#define SCORE_MULTIPLIER_HUNTER 9.0
#define SCORE_MULTIPLIER_RAKKAR 18.0
#define SKILL_LEVEL_GRAPHIC_HEIGHT_FROM_CENTER 15 // How many pixels down center of screen skill graphic for Dead() page will be placed
#define NUMBERS_HIGHSCORE_HEIGHT_FROM_CENTER 25  //  How many pixels up center of screen highscore value for Dead() page will be placed
#define PROX 60.0  // Proximity range, in pixels, that a bomb must reach a target for PROX_TIMER to begin counting down
#define PROX_TIMER 6  // Higher values of this will cause bombs to wait longer before exploding.
#define KEYDOWN(name,key) (name[key] & 0x80) // Macro to read from keyboard

// global variables set by difficulty level.  Can also be set by defines
int STARTING_ROCKS;  // Base number of rocks in addition to an amount based on your level
int BIG_ROCK_HP;  // Base Hitpoints of big rocks
int MEDIUM_ROCK_HP; // Base Hitpoints of medium rocks
int SMALL_ROCK_HP;  // Base Hitpoints of small rocks
int BIG_ROCK_BASE_SPEED;  // Base speed, in pixels per main game loop, of big rocks
int MEDIUM_ROCK_BASE_SPEED;  // Base speed, in pixels per main game loop, of medium rocks
int SMALL_ROCK_BASE_SPEED;  // Base speed, in pixels per main game loop, of small rocks
int MAX_ENERGY;  // Maximum energy for the player
int CHARGE_RATE;  // Charge rate, in units per main game loop, for the player
double WARBIRD_MASS;  //  Mass of the warbird used in determining collisions
int BIG_ROCK_BREAK;  // how many medium rocks the big rock will break into
int MEDIUM_ROCK_BREAK;  // how many small rocks the medium rocks will break into
double CRASH_DAMAGE;  // Damage from a full speed collision
long BIG_ROCK_POINTS;  // variable which holds the score you get for blowing up a big rock
long MEDIUM_ROCK_POINTS;  // variable which holds the score you get for blowing up a medium rock
long SMALL_ROCK_POINTS;  // variable which holds the score you get for blowing up a small rock


#define ROCK_SPAWN_RADIUS 300 // How many pixels a rock can spawn near you at the start of a new level (square rather than circle to avoid floating point)

// Don't touch this
#define OFF     0   // this rock, exhaust, etc. is dead or off
#define ON      1   // this one is alive and in flight
#define EXPLODING 2  // Special flag for exploding bombs

#define BPP 8  // Bits per pixel
#define WINDOW_CLASS_NAME "WINCLASS1"

// PROTOTYPES ////////////////////////////////////////////
int Game_Init(void);  // Starts up all one time variables, loads graphics
int Game_Shutdown(void);  // Locks up the system, don't use it
int Game_Main(void);  // Primary loop
int Title_Screen(void);  // Displays title.bmp in backbuffer.  You still need to use DD_Flip to display it.  I'd recommend manually using the primary buffer instead
void Change_Resolution(int X,int Y, HDC hdc);  // Changes resolution and redisplays the title screen.  Must be called after Game_Init
void error(char *str);  //  Print an error message, delays long enough to read it even with graphics problems, and exits the program.
void Place_Initial_Images(void);  // Initializes variables that need to be set every game.  Must be called before Game_Main
void Start_Level(int level);  // Makes a new set of rocks.  Old rocks will be overwritten
void Move_Rocks(void);  //  Part of Game_Main that was moved out for readability.  Does almost everything, from collision handling to updating rock positions to determing weapon hits
void Draw_Stars(void);  // Draws a bunch of white pixels on the screen.  Assumes directx screen objects and such are already setup by Game_Init
void Draw_Exhaust(void);  // Draws the exhaust from your ship
void Draw_Energy_Bar(void);  // Draws the energy bar at the top of the screen.  Bar is proportional to your energy/MAX_ENERGY ratio
void Draw_Bullets(void);  // Draws and updates bullet graphics.  Does not check for collisions. Will remove decayed bullets though.
void Draw_Bombs(void);  // Draws and updates bomb graphics.  Does not check for collisions. Will remove decayed bomb though.
void Draw_Radar(void);  // Draws your radar.  Uses global flags to determine colors
double arctangent(double x, double y);  // Returns the angle to a point x,y from the center of the coordinate axis
void Draw_Bullet_Flash(void);  // Draws the flashes the bullets make when they hit something.  Removes flashes which reach end of animation chain
void Draw_Explode1(void);  // Same as bullet flash but with explosion type 1 (shorter)
void Draw_Explode2(void);  // Same as bullet flash but with explosion type 2 (longer)
void Draw_Damage(void);  // Draws the little puffs given by destroyed small asteroids
void Create_Medium_Rock(float x, float y);  // Creates a medium rock at x,y.  Globals automatically updated.  Used when large rocks split.
void Create_Small_Rock(float x, float y); // Creates a small rock at x,y.  Globals automatically updated.  Used when medium rocks split.
void Draw_Warp(void);  //  Draws the warp flash when the player warps at 0,0 (center of screen)
void Damage_Player(int dmg);  // Does dmg damage to the player.  Sets destruction flag if player destroyed and resets all ship settings to be ready for a new ship
void Draw_Score(void);  // Draws the digital display in the corner which is used for the player's points
void Title(void);  // Writes the title bitmap image to the backbuffer.  Doesn't do anything else
void About(void);  // Writes the aboyt bitmap image to the primary buffer.  Can be used standalone and will keep the image on the screen without refreshing
void Dead(void);  //  Writes the dead bitmap image to the backbuffer, the highscore, and the difficulty level with that highscore.  Not standalone, but can be if you write to the primary buffer instead
void Draw_Lives(void);  // Draws little shields under score
int Save_Highscores_To_File(char *filename);  // Saves highscores under each difficulty level to the named file
int Load_Highscores_From_File(char *filename);  // Loads highscores under each difficulty level from the named file


// MAIN GLOBAL VARIABLES
HWND main_window_handle = NULL; // save the window handle
HINSTANCE main_instance = NULL; // save the instance
BITMAP_IMAGE energybara; // normal energy bar
BITMAP_IMAGE energybarb; // low energy bar with red thing brighter
BITMAP_IMAGE numbers[10]; // number bitmap array
BITMAP_IMAGE lamer_graphic;  // Holds the graphical word in the lamer.bmp file.  Same for others
BITMAP_IMAGE dueler_graphic;
BITMAP_IMAGE hunter_graphic;
BITMAP_IMAGE rakkar_graphic;
BITMAP_IMAGE title;  // Holds the title screen bitmap data
BITMAP_IMAGE dead;  // Holds the death screen bitmap data
bool start=false;  // TRUE if game has started, false otherwise.
HWND	 hwnd;		// generic window handle
BOB warbird;  // The player
BOB bigrocks[MAX_BIG_ROCKS];  // Bitmap object holding the attibutes of the bigrocks.  Each index of the array is another rock.  Same for medium and small rocks
BOB mediumrocks[MAX_MEDIUM_ROCKS];
BOB smallrocks[MAX_SMALL_ROCKS];
BOB exhaust[EXHAUST_BMP_FRAMES*2];  // Bitmap object used for the animation of the exhaust from your ship
BOB bulletflash[MAX_BULLETS];  // Bitmap object used for the flash from your bullets.
BOB explode1[MAX_BOMBS];  // Bomb explosion
BOB explode2[MAX_EXPLODE2];  // Your ship explosion
BOB damage[MAX_SMALL_ROCKS];  // For now, small rock explosions
BOB bomb[MAX_BOMBS];  // Bitmap object used to hold bombs
BOB warp;  // Not really needed to use a BOB here, but it's easier than creating a bitmap array
BOB shield1;  // holds ssshield.bmp graphic.  Indicates multiple lives
BOB shield2;  // holds shield.bmp graphic indicating 1 life

// sound id's.
int bomb2_id,
    explode0_id,
    explode1_id,
    explode2_id,
    gun3_id,
    rev_id,
    excellent_id;

// global variables used throughout the program
int numberofbigrocks;
int numberofmediumrocks;
int numberofsmallrocks;
int numberofbullets;
int numberofbombs;
int numberofstars;
int bullettimer,bombtimer;
float Acceleration_vector_x_table[40];  // Eliminates need to calculate this during the main loop
float Acceleration_vector_y_table[40];  // Eliminates need to calculate this during the main loop
float sin_table[40];  // Eliminates need to calculate this during the main loop
float cos_table[40];  // Eliminates need to calculate this during the main loop
float sin_ship_projection_table[40];  // Eliminates need to calculate this during the main loop
float cos_ship_projection_table[40];  // Eliminates need to calculate this during the main loop
float sin_bullet_projection_table[40];  // Eliminates need to calculate this during the main loop
float cos_bullet_projection_table[40];  // Eliminates need to calculate this during the main loop
float sin_bomb_projection_table[40];  // Eliminates need to calculate this during the main loop
float cos_bomb_projection_table[40];  // Eliminates need to calculate this during the main loop
char buffer[80];
int halfwidth; int halfheight;
int width,height;
int energy;  // Warbird's Energy
int shipcollision; // Ship collision with asteroid flag.  0 = no collision.  1 = small rock. OR 2 = medium rock. OR  4 = big rock.
int counter;
int BulletflashQueueCounter;
int Explode1QueueCounter;
int Explode2QueueCounter;
int DamageQueueCounter;
int proxtime[MAX_BOMBS]; // holds detonation times for bombs
int level;
int playerdead;
long score;
int lives;
long nextbonuslife;
int skilllevel;
int quit;
long highscore[4];
int thrustsoundplaying;  // ON if thrust sound is currently playing, OFF otherwise
int joystick;  // ON if the joystick is working, OFF otherwise

// This is the warbird's facing from 0 to 39.  Every 1 is 9 degrees.
int warbird_facing=0;  

// Holds x,y positions of the background stars
struct StarStruct {
	float x;
	float y;
	} stars[MAX_STARS];

// Holds the various attributes of your bullets
struct BulletStruct {
	float x;
	float y;
	float xv;
	float yv;
	int lifetime;
	int state;
	int color;
	} bullet[MAX_BULLETS];

// Holds hitpoints for the 3 sizes of the rocks.  rockhp.big[20] would be the hitpoints for the 20th big rock
struct RockHpStruct {
	int big[MAX_BIG_ROCKS];
	int medium[MAX_MEDIUM_ROCKS];
	int small[MAX_SMALL_ROCKS];
	} rockhp;
	// holds hitpoints of rocks



//////////////////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hwnd,
						    UINT msg,
                            WPARAM wparam,
                            LPARAM lparam)
{
// this is the main message handler of the system
PAINTSTRUCT	ps;		   // used in WM_PAINT
 HDC			hdc;	   // handle to a device context

// what is the message
switch(msg)
	{
 	case WM_CREATE:
        {
		// do initialization stuff here
		return(0);
		}// break;

	case WM_PAINT:
		{
		// simply validate the window
		hdc = BeginPaint(hwnd,&ps);
		EndPaint(hwnd,&ps);
		return(0);
   		}// break;

	case WM_DESTROY:
		{
		// kill the application
		PostQuitMessage(0);
		return(0);
		}// break;

   }
return (DefWindowProc(hwnd, msg, wparam, lparam));

} // end WinProc

// WINMAIN ////////////////////////////////////////////////

int WINAPI WinMain(	HINSTANCE hinstance,
					HINSTANCE hprevinstance,
					LPSTR lpcmdline,
					int ncmdshow)
{

WNDCLASS winclass;	// this will hold the class we create
HWND	 hwnd;		// generic window handle
MSG		 msg;		// generic message
HDC      hdc;       // generic dc
PAINTSTRUCT ps;     // generic paintstruct

// first fill in the window class stucture
winclass.style			= CS_DBLCLKS | CS_OWNDC |
                          CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc	= WindowProc;
winclass.cbClsExtra		= 0;
winclass.cbWndExtra		= 0;
winclass.hInstance		= hinstance;
winclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground	= GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName	= NULL;
winclass.lpszClassName	= WINDOW_CLASS_NAME;

// register the window class
if (!RegisterClass(&winclass))
	return(0);

// create the window
if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
						  "Subspace Asteroids",	 // title
						  WS_POPUP | WS_VISIBLE,
					 	  0,0,	   // x,y
						  GetSystemMetrics(SM_CXSCREEN),  // width
                          GetSystemMetrics(SM_CYSCREEN), // height
						  NULL,	   // handle to parent
						  NULL,	   // handle to menu
						  hinstance,// instance
						  NULL)))	// creation parms
return(0);

// save the window handle and instance in a global
main_window_handle = hwnd;
main_instance      = hinstance;

// hide the mouse
ShowCursor(FALSE);

Game_Init();

// Do loop won't work because of bugs in BC5
START:

// Blank the primary buffer
DD_Fill_Surface(lpddsprimary, 0);


			
// Flip the title image from the backbuffer to the screen
// DD_Flip();


	// perform all game console specific initialization
	while(!quit) // Have user select resolution and difficulty
	{
		
		// Refresh the title graphic
		DD_Wait_For_Vsync();
		Title();
		DD_Flip();
		
		DI_Read_Keyboard();  // This will read from the keyboard
		if (keyboard_state[DIK_ESCAPE]) quit=ON;  // User hit esc so let him quit}
	
		else if (keyboard_state[DIK_F1]) About();  // User hit F1.  About is self-contained unlike Title();
   		else if (keyboard_state[DIK_F2])
   	        {
   	        	// Set the various attributes pertaining to playing at this level.  Same comments for each level.
   	        	skilllevel=LAMER;
   	        	
   	        	STARTING_ROCKS=5;
			BIG_ROCK_HP=1000;
			MEDIUM_ROCK_HP=850;
			SMALL_ROCK_HP=350;
			BIG_ROCK_BASE_SPEED=4;
			MEDIUM_ROCK_BASE_SPEED=4;
			SMALL_ROCK_BASE_SPEED=5;
			MAX_ENERGY=2000;
			CHARGE_RATE=4;
			WARBIRD_MASS=200.0;
			BIG_ROCK_BREAK=2;
			MEDIUM_ROCK_BREAK=2;
			CRASH_DAMAGE=1300.0;
			lives=5;

   	        	
              	start=true;
               break;
      	    	 }
      	        else if (keyboard_state[DIK_F3])
   	        {
   	        	
   	        	STARTING_ROCKS=10;
			BIG_ROCK_HP=1200;
			MEDIUM_ROCK_HP=800;
			SMALL_ROCK_HP=410;
			BIG_ROCK_BASE_SPEED=4;
			MEDIUM_ROCK_BASE_SPEED=5;
			SMALL_ROCK_BASE_SPEED=5;
			MAX_ENERGY=1700;
			CHARGE_RATE=3;
			WARBIRD_MASS=100.0;
			BIG_ROCK_BREAK=2;
			MEDIUM_ROCK_BREAK=2;
			CRASH_DAMAGE=1500.0;
			
			lives=3;
   	        	
        	skilllevel=DUELER;
              	start=true;
               break;
   	   	     }
      	        else if (keyboard_state[DIK_F4])
   	        {
   	        	skilllevel=HUNTER;
   	        	
   	        	STARTING_ROCKS=15;
			BIG_ROCK_HP=1500;
			MEDIUM_ROCK_HP=1060;
			SMALL_ROCK_HP=534;
			BIG_ROCK_BASE_SPEED=4;
			MEDIUM_ROCK_BASE_SPEED=6;
			SMALL_ROCK_BASE_SPEED=6;
			MAX_ENERGY=1600;
			CHARGE_RATE=3;
			WARBIRD_MASS=80.0;

			BIG_ROCK_BREAK=2;
			MEDIUM_ROCK_BREAK=3;
			CRASH_DAMAGE=1800.0;
			lives=2;
   	        	
              	start=true;
               break;
      	 	    }
      	        else if (keyboard_state[DIK_F5])
   	        {
   	        	STARTING_ROCKS=20;
			BIG_ROCK_HP=2000;
			MEDIUM_ROCK_HP=1200;
			SMALL_ROCK_HP=600;
			BIG_ROCK_BASE_SPEED=4;
			MEDIUM_ROCK_BASE_SPEED=6;
			SMALL_ROCK_BASE_SPEED=7;
			MAX_ENERGY=1500;
			CHARGE_RATE=3;
			WARBIRD_MASS=50.0;

			BIG_ROCK_BREAK=3;
			MEDIUM_ROCK_BREAK=3;
			CRASH_DAMAGE=2100.0;
			lives=0;
			
   	        	skilllevel=RAKKAR;
              	start=true;
               break;
      	 	 }
	         else if (keyboard_state[DIK_F6] && width!=640)
   	        {
   	        	// Change resolution to 640x480.  Same for each resolution
              		Change_Resolution(640,480,hdc);
      	    	 }
   	      else if (keyboard_state[DIK_F7] && width!=800)
   	        {
              		Change_Resolution(800,600,hdc);
      	    	 }
		else if (keyboard_state[DIK_F8] && width!=1024)
   	        {
              		Change_Resolution(1024,768,hdc);
      	   	  }
		else if (keyboard_state[DIK_F9] && width!=1280)
   	        {
              		Change_Resolution(1280,1024,hdc);
      	   	  }
		else if (keyboard_state[DIK_F10] && width!=1600)
   	        {
              		Change_Resolution(1600,1200,hdc);
      	   	 }
      	   	

	}


	
	// Don't forget to check if the player wanted to quit right away.  This was a major headache debugging when I didn't do it
	if (!quit)
	{
		// PLACE INITIAL IMAGES.  This sets all variables needed to restart a game but does not place rocks
		Place_Initial_Images();

		// Start a new level by placing the rocks
		Start_Level(level++);

		// This is the bad boy that you actually play in.  Assumes settings already correct from Game_Init, Place_Initial_Images, and Start_Level
		Game_Main();
		
		// You just quit or lost the game so update the highscore
		if (score>highscore[skilllevel]) highscore[skilllevel]=score;
		
		// Don't forget to check if the player wanted to quit!
		if (!quit)
		{
			
			// By using the primary surface here, instead of the function call Title which uses the backbuffer, the image will not randomly disappear after a few seconds.  I wish
			// this were documented in the book I was reading...
			DD_Lock_Primary_Surface();
	
			Draw_Bitmap(&title,primary_buffer,primary_lpitch,1);
	
			DD_Unlock_Primary_Surface();
	
			// I can't get the damn loops to work so a good ol' goto saves the day
			goto START;
		}
	}

// Saves highscores to hscores.dat.  File is overwritten
Save_Highscores_To_File("hscores.dat");

// Trying to release resources locks up the system.  Don't bother
// Game_Shutdown();

// Release the joystick
DI_Release_Joystick();

// return to Windows like this
return(msg.wParam);

} // end WinMain

//////////////////////////////////////////////////

int Game_Init(void)
{

int index;  // looping variable

// Set the global variables indicating width and height.
width=GetSystemMetrics(SM_CXSCREEN);
height=GetSystemMetrics(SM_CYSCREEN);

// Store half of each value used in determing graphic placement.
halfwidth=width>>1; halfheight=height>>1;

// Set the number of stars to the maximum number.  At first I scaled this to the volume of the resolution, but found keeping it constant looked better
numberofstars=MAX_STARS;

// Initialize thrust sound flag to off
thrustsoundplaying=OFF;

// Startup DirectInput
DInput_Init();

// Startup the keyboard
DI_Init_Keyboard();

// Startup the joystick
if (!DI_Init_Joystick(-1,1,-1,1)) joystick=OFF;
else joystick=ON;

// Startup DirectSound
DSound_Init();

// Self explanitory
Load_Highscores_From_File("hscores.dat");

// load in bomb wav
if ((bomb2_id = Load_WAV("bomb2.wav"))==-1)
   {error ("Failed to load bomb2.wav");}

// load in small explosion wav
if ((explode0_id = Load_WAV("explode0.wav"))==-1)
   {error ("Failed to load explode0.wav");}

// load in medium explosion wav
if ((explode1_id = Load_WAV("explode1.wav"))==-1)
   {error ("Failed to load explode1.wav");}

// load in big explosion wav
if ((explode2_id = Load_WAV("explode2.wav"))==-1)
   {error ("Failed to load explode2.wav");}
   
// load in gun wav
if ((gun3_id = Load_WAV("gun3.wav"))==-1)
   {error ("Failed to load gun3.wav");}

// load in thrust wav
if ((rev_id = Load_WAV("rev.wav"))==-1)
   {error ("Failed to load rev.wav");}
   
// load in excellent wav
if ((excellent_id = Load_WAV("excellnt.wav"))==-1)
   {error ("Failed to load excellnt.wav");}


// randomize the rand() function
randomize();

// Initialize direct draw to the current resolution.  This will be the resolution the client is running at when the executable is calledd
if (!DD_Init(width,height, BPP)) exit(0);
 	

// START LOADING BMP IMAGES

// Load the graphic used for the player ship.
if (!Load_Bitmap_File(&bitmap8bit, "warbird.bmp")) error("Function Load_Bitmap_File Failure when loading warbird.bmp");
   	
// Use the warbird graphic to set the main palette
Set_Palette(bitmap8bit.palette);
   
// Create the warbird object.  The 36 is the width and height of the object, and the 40 is the number of frames in the bmp file
if (!Create_BOB(&warbird,0,0,36,36,40,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME, DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating Warbird");

// load the animation frames from the bitmap8bit buffer (from the file) into the warbird object buffer.
// The warbird has 40 frames which are spaced 10 per row which is where the 40 and 10 come from
for (index=0; index<40; index++)
{
	if (!Load_Frame_BOB(&warbird,&bitmap8bit,index,index%10,index/10,BITMAP_EXTRACT_MODE_CELL))
      	error("Function Load_Frame_BOB failure with the warbird");
}

// unload data infile
Unload_Bitmap_File(&bitmap8bit);
	
// Now load another bitmap, this used for the warp graphic when a player hits insert
if (!Load_Bitmap_File(&bitmap8bit, "warp.bmp")) error("Function Load_Bitmap_File Failure when loading warp.bmp");
   
// Create the warp image
if (!Create_BOB(&warp,0,0,48,48,WARP_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating Warbird");

   // load warp frames
for (index=0; index<WARP_BMP_FRAMES; index++)
{
	if (!Load_Frame_BOB(&warp,&bitmap8bit,index,index%6,index/6,BITMAP_EXTRACT_MODE_CELL))
      	error("Function Load_Frame_BOB failure with the warp");
}

// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load bmp file for the large sized rocks into the bitmap8bit buffer
if (!Load_Bitmap_File(&bitmap8bit, "rocka.bmp")) error("Function Load_Bitmap_File Failure when loading rocka.bmp");

// Create the big rock object
if (!Create_BOB(&bigrocks[0],0,0,BIG_ROCK_SIZE,BIG_ROCK_SIZE,30,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
               DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating big rock (rocka.bmp)");

// Load the animation frames into the big rock object
for (int frame=0; frame < 30; frame++)
     Load_Frame_BOB(&bigrocks[0],&bitmap8bit,frame,frame%10,frame/10,BITMAP_EXTRACT_MODE_CELL);

// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load bmp file for the medium sized rocks into the bitmap8bit buffer
if (!Load_Bitmap_File(&bitmap8bit, "rockb.bmp")) error("Function Load_Bitmap_File Failure when loading rockb.bmp");

// Create the medium rock object
if (!Create_BOB(&mediumrocks[0],0,0,MEDIUM_ROCK_SIZE,MEDIUM_ROCK_SIZE,30,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating medium rock (rockb.bmp)");

// load medium rock animation frames
for (int frame=0; frame < 30; frame++)
     Load_Frame_BOB(&mediumrocks[0],&bitmap8bit,frame,frame%10,frame/10,BITMAP_EXTRACT_MODE_CELL);

// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load bmp file for the small sized rocks into the bitmap8bit buffer
if (!Load_Bitmap_File(&bitmap8bit, "rockc.bmp")) error("Function Load_Bitmap_File Failure when loading rockc.bmp");

// Create the small rock object
if (!Create_BOB(&smallrocks[0],0,0,SMALL_ROCK_SIZE,SMALL_ROCK_SIZE,30,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating small rock (rockc.bmp)");
               
// Use DDSCAPS_SYSTEMMEMORY to load in system memory.  Use 0 to load into VRAM

// load small rock animation frames into small rock object
for (int frame=0; frame < 30; frame++)
     Load_Frame_BOB(&smallrocks[0],&bitmap8bit,frame,frame%15,frame/15,BITMAP_EXTRACT_MODE_CELL);

// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// REPLICATE ROCKS
// Only index 0 object of the array was created.  Now replicate it for every rock in the array.
for (counter=1; counter<MAX_BIG_ROCKS; counter++)
    {
    memcpy(&bigrocks[counter], &bigrocks[0], sizeof(BOB));

    } // end for rock

for (counter=1; counter<MAX_MEDIUM_ROCKS; counter++)
    {
    memcpy(&mediumrocks[counter], &mediumrocks[0], sizeof(BOB));

    } // end for rock

    for (counter=1; counter<MAX_SMALL_ROCKS; counter++)
    {
    memcpy(&smallrocks[counter], &smallrocks[0], sizeof(BOB));

    } // end for rock


// Load the exhuast bitmap into bitmap8bit buffer	
if (!Load_Bitmap_File(&bitmap8bit, "exhaust.bmp")) error("Function Load_Bitmap_File Failure when loading exhaust.bmp");

// Create the exhaust object	
if (!Create_BOB(&exhaust[0],0,0,16,16,EXHAUST_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating exhaust (exhaust.bmp)");

// load exhaust animation frames into the object
for (int frame=0; frame < EXHAUST_BMP_FRAMES; frame++)
     Load_Frame_BOB(&exhaust[0],&bitmap8bit,frame,frame,0,BITMAP_EXTRACT_MODE_CELL);

// Set the exhaust state to be off so the main loop won't display it     
exhaust[0].state=OFF;

// Replicate the exhaust through the rest of the exhaust array.  Each puff of smoke that comes out when you fly is one exhaust object
for (counter=1; counter<(EXHAUST_BMP_FRAMES<<1); counter++)
{
    memcpy(&exhaust[counter], &exhaust[0], sizeof(BOB));
}

// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load the bullet flash animation for when bullets hit something into the bitmap8bit buffer	
if (!Load_Bitmap_File(&bitmap8bit, "bulletfl.bmp")) error("Function Load_Bitmap_File Failure when loading bulletflash.bmp");

// Create the bullet flash animation object	
if (!Create_BOB(&bulletflash[0],0,0,8,8,BULLET_FLASH_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
               DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating exhaust (bulletflash.bmp)");
         

// load bulletflash animation frames
for (int frame=0; frame < BULLET_FLASH_BMP_FRAMES; frame++)
     Load_Frame_BOB(&bulletflash[0],&bitmap8bit,frame,frame,0,BITMAP_EXTRACT_MODE_CELL);

// Set the state to be off for replication	
bulletflash[0].state=OFF;

// Replicate the bullet flashes.  Note the size of the array for this is the same size as the maximum number of allowed bullets.  This is because you can't have more bullet hit flashes
// than you could bullets
for (counter=1; counter<(MAX_BULLETS); counter++)
{
	memcpy(&bulletflash[counter], &bulletflash[0], sizeof(BOB));
}
	
// unload data infile
Unload_Bitmap_File(&bitmap8bit);
	
// Load the smaller explosion bmp into the bitmap8bit buffer
if (!Load_Bitmap_File(&bitmap8bit, "explode1.bmp")) error("Function Load_Bitmap_File Failure when loading explode1.bmp");

// Create the smaller explosion object	
if (!Create_BOB(&explode1[0],0,0,48,48,EXPLODE1_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating explode1 (explode1flash.bmp)");

// Load the animation froms from the buffer into the object
for (int frame=0; frame < EXPLODE1_BMP_FRAMES; frame++)
     Load_Frame_BOB(&explode1[0],&bitmap8bit,frame,frame%6,frame/6,BITMAP_EXTRACT_MODE_CELL);

// Set status off	
explode1[0].state=OFF;

// Replicate the smaller explosion.  Note that I use the size of the maximum number of allowed bombs as the size of the smaller explosion array.  This is because I use these to represent
// bomb explosions.  If you choose to use the smaller explosion for something else the limit will need to be adjusted accordingly.
for (counter=1; counter<(MAX_BOMBS); counter++)
{
	memcpy(&explode1[counter], &explode1[0], sizeof(BOB));
}

	
// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load the explode2 bmp data into the bitmap8bit buffer	
if (!Load_Bitmap_File(&bitmap8bit, "explode2.bmp")) error("Function Load_Bitmap_File Failure when loading explode2.bmp");

// Create the explode2 (larger explosion) object	
if (!Create_BOB(&explode2[0],0,0,80,80,EXPLODE2_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating explode2 (explode2.bmp)");

// load explode2 animation frames into the object
for (int frame=0; frame < EXPLODE2_BMP_FRAMES; frame++)
     Load_Frame_BOB(&explode2[0],&bitmap8bit,frame,frame%4,frame/4,BITMAP_EXTRACT_MODE_CELL);

// Set state to be off of course	
explode2[0].state=OFF;

// Copy object through the rest of the array of objects
for (counter=1; counter<(MAX_EXPLODE2); counter++)
{
	memcpy(&explode2[counter], &explode2[0], sizeof(BOB));
}

// unload data infile
Unload_Bitmap_File(&bitmap8bit);
	
// This is the yellow shield used to represent multiple lives.  Load it into the bitmap8bit buffer
if (!Load_Bitmap_File(&bitmap8bit, "ssshield.bmp")) error("Function Load_Bitmap_File Failure when loading ssshield.bmp");

// Create the shield1 object.  Although it doesn't move or have many properties, this is easier than creating an array of bitmap images and manually cycling.  It is less efficient though.
if (!Create_BOB(&shield1,0,0,16,16,SHIELD_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating shield1 (shield1.bmp)");

// load shield1 animation frames
for (int frame=0; frame < SHIELD_BMP_FRAMES; frame++)
     Load_Frame_BOB(&shield1,&bitmap8bit,frame,frame%10,frame/10,BITMAP_EXTRACT_MODE_CELL);

// Set the y coordinate of this object to the global SHIELDY.  When I display it later this will be used	
shield1.y=SHIELDY;
	
// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load the shield.bmp data into the bitmap8bit buffer	
if (!Load_Bitmap_File(&bitmap8bit, "shield.bmp")) error("Function Load_Bitmap_File Failure when loading ssshield.bmp");

// Create the shield2 (green rotating thing for 1 life) object	
if (!Create_BOB(&shield2,0,0,16,16,SHIELD_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating shield2 (shield2.bmp)");

// Load shield2 animation frames
for (int frame=0; frame < SHIELD_BMP_FRAMES; frame++)
     Load_Frame_BOB(&shield2,&bitmap8bit,frame,frame%10,frame/10,BITMAP_EXTRACT_MODE_CELL);

// Like before, the shield2 object will have the same y coordinate as the shield1 object.  SHIELDY is a global define	
shield2.y=SHIELDY;

// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load the data from the damage bmp into the bitmap8bit buffer	
if (!Load_Bitmap_File(&bitmap8bit, "damage.bmp")) error("Function Load_Bitmap_File Failure when loading damage.bmp");

// Create the damage object.  This is used as an animated puff of smoke with velocity.  Currently used when small asteroids are destroyed
if (!Create_BOB(&damage[0],0,0,16,16,DAMAGE_BMP_FRAMES,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating damage (damage.bmp)");

// load damage animation frames into damage object
for (int frame=0; frame < DAMAGE_BMP_FRAMES; frame++)
     Load_Frame_BOB(&damage[0],&bitmap8bit,frame,frame%20,frame/20,BITMAP_EXTRACT_MODE_CELL);

// Set state of damage object to off
damage[0].state=OFF;

// Replicate damage object.  Note I use this for small rocks so the absolute maximum possible number that would be on the screen would be the same as the maximum number of rocks.
// This would only happen if you destroyed every rock at the same time, but it's better than crashing
for (counter=1; counter<(MAX_SMALL_ROCKS); counter++)
{
	memcpy(&damage[counter], &damage[0], sizeof(BOB));
}

	
// unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load the bomb graphic (the one you shoot) into the bitmap8bit buffer	
if (!Load_Bitmap_File(&bitmap8bit, "bomb.bmp")) error("Function Load_Bitmap_File Failure when loading bomb.bmp");

// Create the bomb object	
if (!Create_BOB(&bomb[0],0,0,16,16,10,BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,DDSCAPS_SYSTEMMEMORY)) error("Function Create_BOB failure when creating bomb (bomb.bmp)");

// load bomb animation frames into the object from the bitmap8bit buffer
for (int frame=0; frame < 10; frame++)
     Load_Frame_BOB(&bomb[0],&bitmap8bit,frame,frame,0,BITMAP_EXTRACT_MODE_CELL);

// Set bomb status off	
bomb[0].state=OFF;

// Replicate bombs
for (counter=1; counter<(MAX_BOMBS); counter++)
{
	memcpy(&bomb[counter], &bomb[0], sizeof(BOB));
}

	
// unload data infile
Unload_Bitmap_File(&bitmap8bit);
	
// load the number bitmap into the bitmap8bit buffer
if (!Load_Bitmap_File(&bitmap8bit, "numbers.bmp")) error("Function Load_Bitmap_File Failure when loading numbers.bmp");

// Create 10 bitmaps and load images into them.  Each bitmap holds a number graphic corresponding to the index of the array.	
for (counter=0;counter<10;counter++)
{
	Create_Bitmap(&numbers[counter],0,0,16,24);
	Load_Image_Bitmap(&numbers[counter], &bitmap8bit, counter,0,BITMAP_EXTRACT_MODE_CELL);
}

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);

// load the eba bmp graphics into the bitmap 8 bit.  This is the energy bar at the top of the screen without the red thing glowing
if (!Load_Bitmap_File(&bitmap8bit, "eba.bmp")) error("Function Load_Bitmap_File Failure when loading energybara.bmp");

// Create a Bitmap the size of the energybara.bmp file.  Note the image isn't loaded yet
index=Create_Bitmap(&energybara,0,0,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
if (!index)   {error("Function Create_BitMap Failure");}

// Load the data from bitmap8bit into energybara
Load_Image_Bitmap(&energybara, &bitmap8bit, 0,0,1);

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);
   
// Load the other energy bar into bitmap8bit.  This one has the red glowing thing turned on
if (!Load_Bitmap_File(&bitmap8bit, "ebb.bmp")) error("Function Load_Bitmap_File Failure when loading energybarb.bmp");

// Create a Bitmap the size of the energybarb.bmp file.  Note the image isn't loaded yet
index=Create_Bitmap(&energybarb,0,0,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
if (!index)   {error("Function Create_BitMap Failure");}

// Load the data from bitmap8bit into energybarb
Load_Image_Bitmap(&energybarb, &bitmap8bit, 0,0,1);

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);

// Load the 8 bit color bitmap.  This is the word "Lamer" displayed graphically.  It's used at the death scene under the high score
if (!Load_Bitmap_File(&bitmap8bit, "lamer.bmp")) error("Function Load_Bitmap_File Failure when loading lamer.bmp");

// Create a Bitmap object
index=Create_Bitmap(&lamer_graphic,0,0,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
   if (!index)   {error("Function Create_BitMap Failure");}
   
// Load the data from bitmap8bit into energybarb
Load_Image_Bitmap(&lamer_graphic, &bitmap8bit, 0,0,1);

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);
	

// Graphical word "Dueler"
if (!Load_Bitmap_File(&bitmap8bit, "dueler.bmp")) error("Function Load_Bitmap_File Failure when loading dueler.bmp");

// Create a Bitmap object
index=Create_Bitmap(&dueler_graphic,0,0,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
if (!index) {error("Function Create_BitMap Failure");}
   
   
// Load the data from the bitmap into the dueler object
Load_Image_Bitmap(&dueler_graphic, &bitmap8bit, 0,0,1);


// Unload data infile
Unload_Bitmap_File(&bitmap8bit);
	

// Graphical word "Hunter"
if (!Load_Bitmap_File(&bitmap8bit, "hunter.bmp")) error("Function Load_Bitmap_File Failure when loading hunter.bmp");

// Create a Bitmap object
index=Create_Bitmap(&hunter_graphic,0,0,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
if (!index)   {error("Function Create_BitMap Failure");}
   
   
// Load the data from the bitmap into the hunter object
Load_Image_Bitmap(&hunter_graphic, &bitmap8bit, 0,0,1);

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);
	
// Graphical word "Rak'kar"
if (!Load_Bitmap_File(&bitmap8bit, "rakkar.bmp")) error("Function Load_Bitmap_File Failure when loading rakkar.bmp");

// Create a Bitmap object to hold the word
index=Create_Bitmap(&rakkar_graphic,0,0,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
if (!index)   {error("Function Create_BitMap Failure");}

// Load the data from bitmap8bit
Load_Image_Bitmap(&rakkar_graphic, &bitmap8bit, 0,0,1);

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);

// This is the full screen bmp shown when you use up all your lives.
if (!Load_Bitmap_File(&bitmap8bit, "dead.bmp")) error("Function Load_Bitmap_File Failure when loading title.bmp");

// Create the bitmap object.  Notice this time I set the x and y display coordinate attributes.  This will change if the screen resolution changes, and is reset by the change_resolution function
Create_Bitmap(&dead,halfwidth - bitmap8bit.bitmapinfoheader.biWidth / 2,halfheight - bitmap8bit.bitmapinfoheader.biHeight / 2,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);

// Load the data from the bitmap into the dead object
Load_Image_Bitmap(&dead, &bitmap8bit, 0,0,1);

// Unload data infile
Unload_Bitmap_File(&bitmap8bit);

// This is the big title screen graphic.  Has the same properties as the previous graphic (dead)
if (!Load_Bitmap_File(&bitmap8bit, "title.bmp")) error("Function Load_Bitmap_File Failure when loading title.bmp");

// Create the bigmap object.  Once again I go ahead and set the x,y display coordinate attributes right away
index=Create_Bitmap(&title,halfwidth - bitmap8bit.bitmapinfoheader.biWidth / 2,halfheight - bitmap8bit.bitmapinfoheader.biHeight / 2,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
if (!index)   {error("Function Create_BitMap Failure");}

// Load the data from the bitmap into the title object
Load_Image_Bitmap(&title, &bitmap8bit, 0,0,1);
	
// Make sin and cos tables.  Note warbird angles start at top and rotate clockwise.  sin and cos function start at right and rotate counterclockwise
// radians= 2 * PI * (degrees/360)
float degree=90.0;

for (index=0; index<40;index++,degree-=9.0)
{
	// regular sin and cosine table, split into 9 degree increments (40 array elements)
	cos_table[index]=cos(2.0*M_PI*(degree/360.0));
	sin_table[index]=sin(2.0*M_PI*(degree/360.0));
	// sin and cos table distances in pixels of the amount of pixels you should increase your velocity by every main game loop
	Acceleration_vector_x_table[index]=cos_table[index]*ACCELERATION;
	Acceleration_vector_y_table[index]=sin_table[index]*ACCELERATION;
	// sin and cos table distances of how far bullets and bombs should appear away from your ship
	cos_ship_projection_table[index]=cos_table[index]*16.0;  // 16 is half the length of your ship
	sin_ship_projection_table[index]=sin_table[index]*16.0; // 16 is half the length of your ship
	// sin and cos table velocity table of how fast a bullet should move if shot from a certain angle
	cos_bullet_projection_table[index]=cos_table[index]*BULLET_SPEED;  
	sin_bullet_projection_table[index]=sin_table[index]*BULLET_SPEED;
	// same as above but with bombs instead of bullets
	cos_bomb_projection_table[index]=cos_table[index]*BOMB_SPEED;  
	sin_bomb_projection_table[index]=sin_table[index]*BOMB_SPEED;
}

// Shield graphic animations speeds will never change so put them in this one time call function	
Set_Anim_Speed_BOB(&shield1,SHIELD_ANIM_SPEED);
Set_Anim_Speed_BOB(&shield2,SHIELD_ANIM_SPEED);

return(1);
}

//////////////////////////////////////////////////////////

int Game_Shutdown(void)
// Function doesn't work.  Don't use it
{
DD_Shutdown();
Destroy_Bitmap(&energybara);
Destroy_Bitmap(&energybarb);
// Destroy_Bitmap(&title);
for (counter=0;counter<10;counter++) Destroy_Bitmap(&numbers[counter]);

Destroy_BOB(&warbird);
for (counter=0;counter<MAX_BIG_ROCKS;counter++) Destroy_BOB(&bigrocks[counter]);
for (counter=0;counter<MAX_MEDIUM_ROCKS;counter++) Destroy_BOB(&mediumrocks[counter]);
for (counter=0;counter<MAX_SMALL_ROCKS;counter++) Destroy_BOB(&smallrocks[counter]);
for (counter=0;counter<EXHAUST_BMP_FRAMES*2;counter++) Destroy_BOB(&exhaust[counter]);
for (counter=0;counter<MAX_BULLETS;counter++) Destroy_BOB(&bulletflash[counter]);
for (counter=0;counter<MAX_BOMBS;counter++) Destroy_BOB(&explode1[counter]);
for (counter=0;counter<MAX_EXPLODE2;counter++) Destroy_BOB(&explode2[counter]);
for (counter=0;counter<MAX_SMALL_ROCKS;counter++) Destroy_BOB(&damage[counter]);
for (counter=0;counter<MAX_BOMBS;counter++) Destroy_BOB(&bomb[counter]);
Destroy_BOB(&warp);
Destroy_BOB(&shield1);
Destroy_BOB(&shield2);

return (1);
}

////////////////////////////////////////////////////////

int Game_Main(void)
{
int leftframe,rightframe;  // Used to calculate where thrust should appear from
int ExhaustQueueCounter=0,BulletQueueCounter=0,BombQueueCounter=0; // Used to hold position in array for the next element to be put into
float magnitude,scale;
MSG msg;

// For the first call, read data from keyboard.  Not really needed, but just in case
DI_Read_Keyboard();


//////////////////  MAIN GAME LOOP!! ///////////////////////////////////////////////
while (!keyboard_state[DIK_ESCAPE])  // Continue main game loop until user hits escape
{
// Start the timing clock.  This is used to make sure each main game loop takes the same amount of time and runs the same speed on every computer.
Start_Clock();

// Process Windows messages.  I'm not really sure what it does but without it the keyboard will beep and screens disappear
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{ 
		// test if this is a quit
        if (msg.message == WM_QUIT)
           break;
	
		// translate any accelerator keys
		TranslateMessage(&msg);

		// send the message to the window proc
		DispatchMessage(&msg);
		} // end if

// Get input from keyboard
DI_Read_Keyboard();

// Read input from joystick
if (joystick) DI_Read_Joystick();

// If you destroyed all the rocks, reset them using start_level (and go to the next level)
if (numberofsmallrocks==0 && numberofmediumrocks==0 && numberofbigrocks==0) {lives++; Play_Sound(excellent_id); Start_Level(level++);}

// clear the drawing surface
DD_Fill_Surface(lpddsback, 0);

// Skip the normal command functions if you are dead
if (!playerdead)
{
	// If you are waiting to shoot another bullet, decrease the time
	if (bullettimer) bullettimer--;
	
	// If you are waiting to shoot another bomb, decrease the time
	if (bombtimer) bombtimer--;
	
	// If you have less than full energy, increase it
	if (energy<MAX_ENERGY) {energy+=CHARGE_RATE; if (energy>MAX_ENERGY) energy=MAX_ENERGY;}

	// Right arrow key
	if (keyboard_state[DIK_RIGHT] || joy_state.lX > 0)
    	{
    		// The curr_frame attribute holds both the viewable frame and the angle
    		warbird.curr_frame++;
    		
    		// If you turn clockwise past top center, loop the variable over
    		if (warbird.curr_frame==40) warbird.curr_frame=0;
    	}
	// Left Arrow Key
	else if (keyboard_state[DIK_LEFT]  || joy_state.lX < 0)
	{
		// Decrease the angle and animation frame number by one
    		warbird.curr_frame--;
    		
    		// If you turn counterclockwise past top center, loop the variable over
	    	if (warbird.curr_frame==-1) warbird.curr_frame=39;

	}

// vertical/speed motion
if (keyboard_state[DIK_UP] || keyboard_state[DIK_DOWN] || joy_state.lY != 0)
	// if (tickcount-accelerationclock > ACCELERATION_RATE)
    	{
	if (keyboard_state[DIK_UP] || joy_state.lY < 0)
	{
    		// accelerationclock=tickcount;
    		warbird.yv-=Acceleration_vector_y_table[warbird.curr_frame];
    		warbird.xv+=Acceleration_vector_x_table[warbird.curr_frame];
    	}
    	else 
    	{
    		// accelerationclock=tickcount;
    		warbird.yv+=Acceleration_vector_y_table[warbird.curr_frame];
    		warbird.xv-=Acceleration_vector_x_table[warbird.curr_frame];
    	}
    	// calculate current velocity vector magnitude

    	magnitude=sqrt(warbird.yv*warbird.yv + warbird.xv*warbird.xv);
    	// scale down to MAXSPEED if over the limit
    	if (magnitude > MAXSPEED) {scale=MAXSPEED / magnitude; warbird.yv*=scale; warbird.xv*=scale;}

    	// Use this to offset thrusters from center
    	leftframe=warbird.curr_frame-2;
	rightframe=warbird.curr_frame+2;

    	if (leftframe<0) leftframe+=40;
    	if (rightframe>39) rightframe-=40;

	// Set and offset exhaust exit coordinates (relative to warbird at 0,0)
	// ship_projection_table is the sin or cosine table * 16, half the length of your ship
    	exhaust[ExhaustQueueCounter].state=ON;
    	exhaust[ExhaustQueueCounter].y=(sin_ship_projection_table[leftframe]);
    	exhaust[ExhaustQueueCounter].x=-(cos_ship_projection_table[leftframe]);
    	exhaust[ExhaustQueueCounter].xv=Acceleration_vector_x_table[warbird.curr_frame];
    	exhaust[ExhaustQueueCounter].yv=-Acceleration_vector_y_table[warbird.curr_frame];
    	
    	// 2nd thruster
    	exhaust[ExhaustQueueCounter+1].state=ON;
    	exhaust[ExhaustQueueCounter+1].y=(sin_ship_projection_table[rightframe]);
    	exhaust[ExhaustQueueCounter+1].x=-(cos_ship_projection_table[rightframe]);
    	exhaust[ExhaustQueueCounter+1].xv=Acceleration_vector_x_table[warbird.curr_frame];
    	exhaust[ExhaustQueueCounter+1].yv=-Acceleration_vector_y_table[warbird.curr_frame];
    	
    	ExhaustQueueCounter+=2;
    	if ((ExhaustQueueCounter)==(EXHAUST_BMP_FRAMES<<1)) ExhaustQueueCounter=0;
    	
    	// Play thrust sound
    	if (!thrustsoundplaying) {Play_Sound(rev_id,DSBPLAY_LOOPING);  thrustsoundplaying=ON;}


	} // end if
else if (thrustsoundplaying) {Stop_Sound(rev_id); thrustsoundplaying=OFF;}

// test if player is firing.  bullettimer is used to limit the player's rate of fire
if ((keyboard_state[DIK_LCONTROL] || keyboard_state[DIK_RCONTROL] || joy_state.rgbButtons[0]) && (!bullettimer) && energy>=BULLET_COST && numberofbullets<=MAX_BULLETS)
	{
		// Subtract energy cost of bullet from player's energy
		energy-=BULLET_COST;
		
		// Reset the bullet timer
		bullettimer=BULLET_ITERATION;
		
		// Increase global variable tracking number of active bullets
		numberofbullets++;
		
		// Setup bullet properties for a new bullet
		bullet[BulletQueueCounter].state=ON;  // Bullet is active
    		bullet[BulletQueueCounter].y=-sin_ship_projection_table[warbird.curr_frame];  // Sets y coord of bullet to be out of nose
	    	bullet[BulletQueueCounter].x=cos_ship_projection_table[warbird.curr_frame];  // Sets x coord of bullet to also be out of the nose
    		bullet[BulletQueueCounter].xv=cos_bullet_projection_table[warbird.curr_frame]+warbird.xv;  // horizontal velocity vector
		bullet[BulletQueueCounter].yv=-sin_bullet_projection_table[warbird.curr_frame]+warbird.yv;  // vertical velocity vector
	    	bullet[BulletQueueCounter].lifetime=0;  // Holds bullet lifetime.  When reaches BULLET_LIFETIME bullet will expire
	    	bullet[BulletQueueCounter].color=LOWER_PALETTE_BULLET_COLOR;  // Will start from this and go up to UPPER_PALETTE_BULLET_COLOR
	    	
	    	// Just loops through the array to find an unused element
	    	BulletQueueCounter++;
    		if ((BulletQueueCounter)==(MAX_BULLETS)) BulletQueueCounter=0;
    		
    		// Play bullet sound
    		Play_Sound(gun3_id);
	}

if ((keyboard_state[DIK_TAB] || joy_state.rgbButtons[1]) && (!bombtimer) && energy>=BOMB_COST && numberofbombs<=MAX_BOMBS)
	{
		
	// Everything here is exactly the same as for bullets
	
		energy-=BOMB_COST;
		bombtimer=BOMB_ITERATION;
		bullettimer=BULLET_ITERATION*3;
		numberofbombs++;
		warbird.yv+=Acceleration_vector_y_table[warbird.curr_frame] * RECOIL_STRENGTH;
	    	warbird.xv-=Acceleration_vector_x_table[warbird.curr_frame] * RECOIL_STRENGTH;
	    	
	    	magnitude=sqrt(warbird.yv*warbird.yv + warbird.xv*warbird.xv);
	    	// scale down to MAXSPEED if over the limit
    		if (magnitude > MAXSPEED) {scale=MAXSPEED / magnitude; warbird.yv*=scale; warbird.xv*=scale;}
				
		bomb[BombQueueCounter].state=ON;
    		bomb[BombQueueCounter].y=-sin_ship_projection_table[warbird.curr_frame];
	    	bomb[BombQueueCounter].x=cos_ship_projection_table[warbird.curr_frame];
    		bomb[BombQueueCounter].xv=cos_bomb_projection_table[warbird.curr_frame]+warbird.xv;
		bomb[BombQueueCounter].yv=-sin_bomb_projection_table[warbird.curr_frame]+warbird.yv;
	    	bomb[BombQueueCounter].anim_index=0;  // Holds bomb lifetime.  When reaches BOMB_LIFETIME bomb will expire
	    	bomb[BombQueueCounter].curr_frame=0;
	    	proxtime[BombQueueCounter]=0;
	    	
	    	BombQueueCounter++;
    		if ((BombQueueCounter)==(MAX_BOMBS)) BombQueueCounter=0;
		
		// Play bomb sound
		Play_Sound(bomb2_id);
	}

if ((keyboard_state[DIK_INSERT] || joy_state.rgbButtons[2]) && energy==MAX_ENERGY)
	{
		// Warping takes all your energy
		energy=1;
		
		// Start a new level
		Start_Level(level++);
		
		// This is used as a flag to show the warp graphic
		warp.state=ON;
	}
	

}  // end of if (!playerdead)

else if (keyboard_state[DIK_SPACE] || joy_state.rgbButtons[3])
	{
		// playerdead is a flag.  When on the loop knows not to show certain graphics, such as the ship itself
		if (lives!=-1) playerdead=OFF;
		
		// lives is -1 which means you died without spare lives.  This quits the main loop
		else return 1;
	}
	
// Whatever goes first will be most in the background.
// Draw the white dots in the background.  Everything goes over this
Draw_Stars();

// Draw the spinning logos representing spare lives
if (lives) Draw_Lives();  // Don't bother calling the function if you have no bonus lives

// Move the rocks.  Also sets bomb timers if they reach prox range and handles bullet collisions.
Move_Rocks();

// Draw and animate the exhaust fumes from your engines
Draw_Exhaust();

// Simply animates and updates bullet positions.  Actual contact is handled in Move_Rocks()
Draw_Bullets();

// Moves active bombs and explodes bombs with explosion flag set.  Exploding bombs damage all targets within prox radius
Draw_Bombs();

//  Draws the player's ship as long as you aren't dead
if (!playerdead) Draw_BOBXY(&warbird,lpddsback,halfwidth,halfheight);

// Draws and animates the flashes given off by bullets when they hit something
Draw_Bullet_Flash();

// Draws the puffs given off by exploding small rocks
Draw_Damage();

// Draws the smaller explosions given off by exploding bombs
Draw_Explode1();

// Draws the larger explosion given off when you die
Draw_Explode2();

// Draw score if you are dead but have lives.  Don't draw if you are dead and don't have lives OR if you have no score
if (lives!=-1)
	{
	if (score) Draw_Score();
	}
else Dead();

if (!playerdead)
{
 Draw_Radar();
 Draw_Energy_Bar();
 if (warp.state==ON) Draw_Warp();
}

// Show everything drawn to the backbuffer by prior graphics function calls
DD_Flip();

// sync to 30ish fps.  Changing this will also change the speed of the game.
Wait_Clock(GAME_RATE);
// sleep(1);
}

// Player hit escape
 quit=ON;
// return success
return(1);

} // end Game_Main


///////////////////////////////////////////////////////////

void Change_Resolution(int X,int Y,HDC hdc)
{
int ScreenWidth;
int ScreenHeight;

// Store the current screen width and height in case the user tries to select an unsupported display mode
ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
ScreenHeight = GetSystemMetrics(SM_CYSCREEN);

// Change to the selected display mode, given from the main page by F6 to F10
if ((lpdd->SetDisplayMode(X,Y,SCREEN_BPP))!=DD_OK)
	{
   	error("Cannot Support requested resolution!");
	   if ((lpdd->SetDisplayMode(ScreenWidth,ScreenHeight,SCREEN_BPP))!=DD_OK) exit(1);
   }

// Store the new screen dimensions
width=GetSystemMetrics(SM_CXSCREEN);
halfwidth=width/2;
height=GetSystemMetrics(SM_CYSCREEN);
halfheight=height/2;

// buffers need to be reallocated.  Deallocate resources for former resolution first
// release the clipper
if (lpddclipper)
    lpddclipper->Release();

// release the secondary surface
if (lpddsback)
    lpddsback->Release();

// release the primary surface
if (lpddsprimary)
   lpddsprimary->Release();

// Create the primary surface
memset(&ddsd,0,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

// we need to let dd know that we want a complex 
// flippable surface structure, set flags for that
ddsd.ddsCaps.dwCaps =
  DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;

// set the backbuffer count to 1
ddsd.dwBackBufferCount = 1;

// create the primary surface
lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);

// query for the backbuffer i.e the secondary surface
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);

// clear out both primary and secondary surfaces
DD_Fill_Surface(lpddsprimary,0);
DD_Fill_Surface(lpddsback,0);

// Reset the center coordinates for the title and dead graphics
title.x=halfwidth - bitmap8bit.bitmapinfoheader.biWidth / 2;
title.y=halfheight - bitmap8bit.bitmapinfoheader.biHeight / 2;
dead.x=halfwidth - bitmap8bit.bitmapinfoheader.biWidth / 2;
dead.y=halfheight - bitmap8bit.bitmapinfoheader.biHeight / 2;

// Reset clipper
RECT screen_rect={0,0,width,height};
lpddclipper=DD_Attach_Clipper(lpddsback,1,&screen_rect);

// Put title on backbuffer
Title();

// Show it
DD_Flip();

}

void error(char *str)
{
	// Quit and dirty but does the job.  If any serious errors occur this will display the error message despite graphic resolution, wait long enough for the user to read it
	// and quit

        HDC hdc;
        // print out the key on the screen
        hdc = GetDC(hwnd);

        // set the colors
        SetTextColor(hdc, RGB(0,255,0));
        SetBkColor(hdc,RGB(0,0,0));
        SetBkMode(hdc,OPAQUE);

        // output the message
        TextOut(hdc,0,0,str,strlen(str));
        sleep(5);

        // release dc
        ReleaseDC(hwnd,hdc);
        exit(1);
 }

/////////////////////////////////////////////////////////////////////////////        
        
void Place_Initial_Images(void)
// Actually a secondary initilization which can assume screen resolution and other front screen options are selected
{

// Get width and height again, just in case
width=GetSystemMetrics(SM_CXSCREEN);
height=GetSystemMetrics(SM_CYSCREEN);
halfheight=height>>1; halfwidth=width>>1;

// Make sure the global qutting flag is off
quit=OFF;


BIG_ROCK_POINTS=10L; // Initial values
MEDIUM_ROCK_POINTS=20L;  // Initial values
SMALL_ROCK_POINTS=40L;  // Initial values

// Use temporary floats to eliminate round error then change to int and assign to globals
float BRP=BIG_ROCK_POINTS;
float MRP=MEDIUM_ROCK_POINTS;
float SRP=SMALL_ROCK_POINTS;

// Adjust points by screen width
if (width==1600) {BRP*=SCORE_MULTIPLIER_1600x1200; MRP*=SCORE_MULTIPLIER_1600x1200; SRP*=SCORE_MULTIPLIER_1600x1200;}
else if (width==1280) {BRP*=SCORE_MULTIPLIER_1280x1024; MRP*=SCORE_MULTIPLIER_1280x1024; SRP*=SCORE_MULTIPLIER_1280x1024;}
else if (width==1024) {BRP*=SCORE_MULTIPLIER_1024x768; MRP*=SCORE_MULTIPLIER_1024x768; SRP*=SCORE_MULTIPLIER_1024x768;}
else if (width==800) {BRP*=SCORE_MULTIPLIER_800x600; MRP*=SCORE_MULTIPLIER_800x600; SRP*=SCORE_MULTIPLIER_800x600;}
else {BRP*=SCORE_MULTIPLIER_640X480; MRP*=SCORE_MULTIPLIER_640X480; SRP*=SCORE_MULTIPLIER_640X480;}


// Adjust points by difficulty level
if (skilllevel==LAMER) {BRP*=SCORE_MULTIPLIER_LAMER; MRP*=SCORE_MULTIPLIER_LAMER; SRP*=SCORE_MULTIPLIER_LAMER;}
else if (skilllevel==DUELER) {BRP*=SCORE_MULTIPLIER_DUELER; MRP*=SCORE_MULTIPLIER_DUELER; SRP*=SCORE_MULTIPLIER_DUELER;}
else if (skilllevel==HUNTER) {BRP*=SCORE_MULTIPLIER_HUNTER; MRP*=SCORE_MULTIPLIER_HUNTER; SRP*=SCORE_MULTIPLIER_HUNTER;}
else {BRP*=SCORE_MULTIPLIER_RAKKAR; MRP*=SCORE_MULTIPLIER_RAKKAR; SRP*=SCORE_MULTIPLIER_RAKKAR;}

// These are the final values used for your scoring
BIG_ROCK_POINTS=(long) BRP;
MEDIUM_ROCK_POINTS=(long) MRP;
SMALL_ROCK_POINTS=(long) SRP;


// Setup warbird properties.  warbird.curr_frame servers both as the frame and as the heading in increments of 9*warbird.curr_frame degrees
warbird.xv=0.0; warbird.yv=0.0; warbird.curr_frame=0; energy=MAX_ENERGY;

// Reset timers and other global counters
bullettimer=0;  bombtimer=0; numberofbullets=0; numberofbombs=0; shipcollision=0;

// Set the position of the energy bars
energybara.x=halfwidth - energybara.width / 2;
energybara.y=ENERGY_BAR_DOWNSET;
energybarb.x=halfwidth - energybarb.width / 2;
energybarb.y=ENERGY_BAR_DOWNSET;

// Set all array queue trackers to 0 (index 0 of the array).
BulletflashQueueCounter=0;
Explode1QueueCounter=0;
Explode2QueueCounter=0;
DamageQueueCounter=0;

// set the flag used to display the warp graphic off
warp.state=OFF;

// Set the flag that tells whether the player is dead or not to off
playerdead=OFF;

// New games start at level 1
level=1;

// Player's score starts at 0
score=0;

// Position high score skill level graphics for Dead() screen
lamer_graphic.x=halfwidth-lamer_graphic.width/2;
lamer_graphic.y=halfheight+SKILL_LEVEL_GRAPHIC_HEIGHT_FROM_CENTER;
dueler_graphic.x=halfwidth-dueler_graphic.width/2;
dueler_graphic.y=halfheight+SKILL_LEVEL_GRAPHIC_HEIGHT_FROM_CENTER;
hunter_graphic.x=halfwidth-hunter_graphic.width/2;
hunter_graphic.y=halfheight+SKILL_LEVEL_GRAPHIC_HEIGHT_FROM_CENTER;
rakkar_graphic.x=halfwidth-rakkar_graphic.width/2;
rakkar_graphic.y=halfheight+SKILL_LEVEL_GRAPHIC_HEIGHT_FROM_CENTER;


// Set the explosion graphics to off and at the first frame
for (counter=0;counter<MAX_BOMBS;counter++) {explode1[counter].state=OFF; explode1[counter].curr_frame=0;}
for (counter=0;counter<MAX_EXPLODE2;counter++) {explode2[counter].state=OFF; explode2[counter].curr_frame=0;}

// Turn off possible residual bullets or bombs
for (counter=0;counter<MAX_BULLETS;counter++) {bullet[counter].state=OFF;}
for (counter=0;counter<MAX_BOMBS;counter++) {bomb[counter].state=OFF;}

// Set the y coordinates of the number graphics to a fixed value.  The x coordinate changes depending on the position of the numeral
for (counter=0;counter<10;counter++)
	{
		numbers[counter].y=ENERGY_BAR_DOWNSET+12;

	}

   // Create the stars
   for (counter=0;counter<numberofstars;counter++)
   {
   	stars[counter].x=(float)(rand()%(MAXX*2))-MAXX;
   	stars[counter].y=(float)(rand()%(MAXY*2))-MAXY;
   }
   
}

/////////////////////////////////////////////////////////////////////////////

void Start_Level(int level)
{
float x,y;


// Determine how many rocks the level will have
 numberofbigrocks=STARTING_ROCKS+level;

if (numberofbigrocks>=MAX_BIG_ROCKS) numberofbigrocks=MAX_BIG_ROCKS;

numberofmediumrocks=STARTING_ROCKS+2*level;
if (numberofmediumrocks>=MAX_MEDIUM_ROCKS) numberofmediumrocks=MAX_MEDIUM_ROCKS;


numberofsmallrocks=STARTING_ROCKS+4*level;
if (numberofsmallrocks>=MAX_SMALL_ROCKS) numberofsmallrocks=MAX_SMALL_ROCKS;

// Randomly set attributes for each big rock
for (counter=0;counter<numberofbigrocks;counter++)
{
   // How fast the rock spins.  Higher values mean the rock spins more slowly
   Set_Anim_Speed_BOB(&bigrocks[counter],2+rand()%4);
   
   // How fast the rock moves.  First argument in function call is for the x velocity vector. Second is for y
   Set_Vel_BOB(&bigrocks[counter], (-BIG_ROCK_BASE_SPEED) + ( rand() % (BIG_ROCK_BASE_SPEED*2+1) ), (-BIG_ROCK_BASE_SPEED) + ( rand() % (BIG_ROCK_BASE_SPEED*2+1) ));
   
   // Set random positions for the rock, but make sure it's not too close to 0,0 - the fixed position of the player
   do
   {
   	x=MAXX-rand()%(MAXX<<1);
   	y=MAXY-rand()%(MAXY<<1);
   }
   while ((fabs(warbird.x-x) < ROCK_SPAWN_RADIUS) && (fabs(warbird.y-y) < ROCK_SPAWN_RADIUS));
   
   // hp of rock - half the range + a random percent of the range
   rockhp.big[counter]=BIG_ROCK_HP - (ROCK_HP_RANGE/2 * BIG_ROCK_HP) + (rand() % (int)(ROCK_HP_RANGE * BIG_ROCK_HP));
   	
   Set_Pos_BOB(&bigrocks[counter], x,y);
   bigrocks[counter].state = ON;
}


// Randomly set attributes for each medium rock.
for (counter=0;counter<numberofmediumrocks;counter++)
{
	Set_Anim_Speed_BOB(&mediumrocks[counter],1+rand()%4);
  Set_Vel_BOB(&mediumrocks[counter], (-MEDIUM_ROCK_BASE_SPEED) + ( rand() % (MEDIUM_ROCK_BASE_SPEED*2+1) ), (-MEDIUM_ROCK_BASE_SPEED) + ( rand() % (MEDIUM_ROCK_BASE_SPEED*2+1) ));
   //Set_Vel_BOB(&mediumrocks[counter], 0, 0 );

   // make sure rocks don't spawn too close to player
   do
   {
	x=MAXX-rand()%(MAXX<<1);
   	y=MAXY-rand()%(MAXY<<1);
   }
   	while ((fabs(x) < ROCK_SPAWN_RADIUS) && (fabs(y) < ROCK_SPAWN_RADIUS));

	// hp of rock - half the range + a random percent of the range
   rockhp.medium[counter]=MEDIUM_ROCK_HP - (ROCK_HP_RANGE/2 * MEDIUM_ROCK_HP) +(rand() % (int)(ROCK_HP_RANGE * MEDIUM_ROCK_HP));


   Set_Pos_BOB(&mediumrocks[counter], x,y);
   mediumrocks[counter].state = ON;
}

// Randomly set attributes for each small rock
for (counter=0;counter<numberofsmallrocks;counter++)
{
	Set_Anim_Speed_BOB(&smallrocks[counter],1+rand()%3);
   Set_Vel_BOB(&smallrocks[counter], (-SMALL_ROCK_BASE_SPEED) + ( rand() % (SMALL_ROCK_BASE_SPEED*2+1) ), (-SMALL_ROCK_BASE_SPEED) + ( rand() % (SMALL_ROCK_BASE_SPEED*2+1) ));
//   Set_Vel_BOB(&smallrocks[counter], 0, 0 );
   do
   {
	x=MAXX-rand()%(MAXX<<1);
   	y=MAXY-rand()%(MAXY<<1);
   }
   	while ((fabs(warbird.x-x) < ROCK_SPAWN_RADIUS) && (fabs(warbird.y-y) < ROCK_SPAWN_RADIUS));

	// hp of rock - half the range + a random percent of the range
   	rockhp.small[counter]=SMALL_ROCK_HP - (ROCK_HP_RANGE/2 * SMALL_ROCK_HP) + (rand() % (int)(ROCK_HP_RANGE * SMALL_ROCK_HP));
   	
   Set_Pos_BOB(&smallrocks[counter], x,y);
   smallrocks[counter].state = ON;
}
}

/////////////////////////////////////////////////////////////////////////////

void Move_Rocks(void)
{
//  This function moves the rocks, updates the graphics for them, detects collisions, handles rocks destroyed from collions or bullets, and draws bullet and bomb explosion graphics
//  It does not process bomb explosion damage, that is done in Move_Bombs	


	int counter2;  // A general counter, primarily used in this function to cycle through bullets
	double angle,distance;
	double dmg;
	

	counter=0;

// This is used for a goto needed to break the cycle of checking for rock damage if a rock is destroyed by an earlier method, such as the player crashing into it.  Without it,
// the optimization of removing gaps in the big/medium/smallrocks array would result in the wrong element being processed as soon as the gap is filled.  If the process is allowed to
// continue, the first half would occur on the first rock and the second half the second.  For example, if the player crashed into a rock and destroyed it without the goto
// the function would go onto checking bullets for a different rock but never check for crashing into it.  This was a source of random lockups until I discovered it
STARTBIGROCKS:
	for (;counter<numberofbigrocks;counter++)
	{

		// Move rock by delta v.  Note all rock position is relative to warbird
		bigrocks[counter].x+=bigrocks[counter].xv-warbird.xv;
		bigrocks[counter].y+=bigrocks[counter].yv-warbird.yv;
		// Flip rock through virtual subspace.  Note the player doesn't know the difference
		if (fabs(bigrocks[counter].x)>=MAXX) bigrocks[counter].x=-bigrocks[counter].x;
		if (fabs(bigrocks[counter].y)>=MAXY) bigrocks[counter].y=-bigrocks[counter].y;

		// If rock is close enough to be visible then display and animate it
		if (fabs(bigrocks[counter].y)<((halfheight) + (BIG_ROCK_SIZE>>1)) &&
		    fabs(bigrocks[counter].x)<((halfwidth) + (BIG_ROCK_SIZE>>1)))
		    {
	   	
		    	// I could change the frame manually, but this takes care of waiting cycles for rocks which rotate more slowly than once per cycle
		    	Animate_BOB(&bigrocks[counter]);
		    	
		    	// Loop the frame if needed of course
		    	if (bigrocks[counter].curr_frame==30) bigrocks[counter].curr_frame=0;
				    	
			// Display the rock in its new position
		    	Draw_BOBXY(&bigrocks[counter],lpddsback,(halfwidth)+bigrocks[counter].x,(halfheight)+bigrocks[counter].y);

		    	// Check for ship collisions by checking to see if the rock x,y position is too close to 0,0
		    	// Too close is defined by half the size of the rock plus half the size of your ship (8)
		    	// Since rock positions are updated even when a player is dead, make sure the player is not dead before performing the collision detection routine.
		    	if ((fabs(bigrocks[counter].x) <= (BIG_ROCK_SIZE>>1) + 8) &&
		    	    (fabs(bigrocks[counter].y) <= (BIG_ROCK_SIZE>>1) + 8)  && !playerdead)				    	
		    	{
				    		
				// need a temporary holder to exchange values
				double tempa,tempb,tempc,tempd,warbirda,warbirdb,magnitude;


				// elastic collsion formula, divided into 2D vectors.
				tempa=((WARBIRD_MASS-BIG_ROCK_MASS) / (WARBIRD_MASS+BIG_ROCK_MASS)) * warbird.xv + ((BIG_ROCK_MASS * 2.0) / (WARBIRD_MASS+BIG_ROCK_MASS)) * bigrocks[counter].xv;
				tempb=((WARBIRD_MASS-BIG_ROCK_MASS) / (WARBIRD_MASS+BIG_ROCK_MASS)) * warbird.yv + ((BIG_ROCK_MASS * 2.0) / (WARBIRD_MASS+BIG_ROCK_MASS)) * bigrocks[counter].yv;
				tempc=((WARBIRD_MASS*2.0) / (WARBIRD_MASS+BIG_ROCK_MASS)) * warbird.xv + ((BIG_ROCK_MASS-WARBIRD_MASS) / (WARBIRD_MASS+BIG_ROCK_MASS)) * bigrocks[counter].xv;
				tempd=((WARBIRD_MASS*2.0) / (WARBIRD_MASS+BIG_ROCK_MASS)) * warbird.yv + ((BIG_ROCK_MASS-WARBIRD_MASS) / (WARBIRD_MASS+BIG_ROCK_MASS)) * bigrocks[counter].yv;
	
				
				// This is the angle of refraction used in the next line
				// Also, the built in tan function doesn't work right to determine angles so I wrote the arctangent function which will translate the output into the standard
				// 2 PI radians going counterclockwise from left.
				angle = arctangent(bigrocks[counter].x,bigrocks[counter].y);
				
				// apply the angle of refraction to determine the component change of the velocity vector and apply it ot the rock.
				bigrocks[counter].xv-=(fabs(cos(angle)))*(bigrocks[counter].xv-tempc);
				bigrocks[counter].yv-=(fabs(sin(angle)))*(bigrocks[counter].yv-tempd);

				// warbird and rock temporary values are stored in order to compute damage
				warbirda=(fabs(cos(angle)))*(warbird.xv-tempa);
				warbirdb=(fabs(sin(angle)))*(warbird.yv-tempb);
							
				// Damage player ship
				// Collision strength is based on magnitude of the vector differences.
				// First, determine magnitude of collision
				magnitude=sqrt(warbirda*warbirda+warbirdb*warbirdb);
				// Now compute damage.  It's proportional to the maximum velocity that your ship is moved
				dmg=(magnitude/MAXSPEED)*CRASH_DAMAGE;
				
				// This function both damages you and handles it if you die
				Damage_Player((int)dmg);
				
				// As long as you didn't die apply your velocity change.  If you did die don't apply it so your explosion will fly over the rock in a cool fashion.
				if (!playerdead) {warbird.xv-=warbirda;	warbird.yv-=warbirdb;}
			
				// Damage the rock too
				rockhp.big[counter]-=(int)dmg;
				
				// If the rock died, so to speak
				if (rockhp.big[counter]<=0)
	    			{
    							
    					// Split rock into medium chunks
    					int counter3;
    					for (counter3=0;counter3<BIG_ROCK_BREAK;counter3++) Create_Medium_Rock(bigrocks[counter].x,bigrocks[counter].y);	
	    							
		    			// remove big rock
	    				numberofbigrocks--;
    							
    					// Compact list by moving last element into destroyed element.  This is an optimization with many EXTREMELY hard to track down
    					// random potential bugs so be VERY careful about touching it
    					if (counter!=numberofbigrocks)
    					{
    						memcpy(&bigrocks[counter], &bigrocks[numberofbigrocks], sizeof(BOB));
	    					rockhp.big[counter]=rockhp.big[numberofbigrocks];
	    					counter--;
	    				}
	    				continue;  // Go to next rock now.
    				}
    						
				// Move the rock a little away to prevent getting stuck.
				else if (!playerdead)
				do
				{
					// The direction the rock moves depends on its position relative to you
				    	if (sin(angle)>=.69) {bigrocks[counter].y-=2;}
				    	else if (sin(angle)<=-.69) {bigrocks[counter].y+=2;}
				    	if (cos(angle)>=.69) {bigrocks[counter].x+=2;}
				    	else if (cos(angle)<=-.69) {bigrocks[counter].x-=2;}

				}

				// Perform another collision detection.  If still hit, move rock out of the way
				while ((fabs(bigrocks[counter].x) <= (BIG_ROCK_SIZE>>1) + 8) &&
					(fabs(bigrocks[counter].y) <= (BIG_ROCK_SIZE>>1) + 8));

			}
			// PERFORM BULLET COLLISION CHECKING
			for (counter2=0;counter2<MAX_BULLETS;counter2++)	
				if (bullet[counter2].state==ON)
				{
					// Basically check a square to see if the bullet is in hitting range
					// I found the -1 is needed because of the way the image displays
					// from the Draw_BobXY function
					if (bullet[counter2].x >= bigrocks[counter].x-(BIG_ROCK_SIZE>>1) &&
					    bullet[counter2].x <= bigrocks[counter].x+(BIG_ROCK_SIZE>>1)-1 &&
					    bullet[counter2].y >= bigrocks[counter].y-(BIG_ROCK_SIZE>>1) &&
					    bullet[counter2].y <= bigrocks[counter].y+(BIG_ROCK_SIZE>>1)-1)
					{
						// place bullet flash
						bulletflash[BulletflashQueueCounter].state=ON;
					    	bulletflash[BulletflashQueueCounter].y=bullet[counter2].y;
    						bulletflash[BulletflashQueueCounter].x=bullet[counter2].x;
    						
    						// remove bullet
    						bullet[counter2].state=OFF;
    						numberofbullets--;
    						
    						// Move array index over
    						BulletflashQueueCounter++;
    						if ((BulletflashQueueCounter)==(MAX_BULLETS)) BulletflashQueueCounter=0;
    						
    						// Compute the damage.
						dmg=BULLET_DAMAGE;
						if (rand()%2) dmg-=rand() % (int)(BULLET_DAMAGE_RANGE*dmg);
						else dmg+=rand() % (int)(BULLET_DAMAGE_RANGE*dmg);
						
						// Apply the damage
						rockhp.big[counter]-=dmg;
						
						// This is the same as before.  Damage the rock, split it, compact the list, add to your score, and play the explosion sound
    						if (rockhp.big[counter]<=0)
	    						{
    							
    								// Split rock into chunks
    								int counter3;
    								for (counter3=0;counter3<BIG_ROCK_BREAK;counter3++) Create_Medium_Rock(bigrocks[counter].x,bigrocks[counter].y);	
	    						
	    							// remove big rock
    								numberofbigrocks--;
    							
    								// compact list by moving last element into destroyed element
    								if (counter!=numberofbigrocks)
    								{
    								memcpy(&bigrocks[counter], &bigrocks[numberofbigrocks], sizeof(BOB));
	    							rockhp.big[counter]=rockhp.big[numberofbigrocks];
	    							}
	    							
	    							score+=BIG_ROCK_POINTS;
	    							
	    							// Play rock explosion sound
	    							Play_Sound(explode1_id);
	    							//if (Explode1QueueCounter==MAX_EXPLOSION_SOUNDS) Explode1QueueCounter=0;
	    							
	    							// This goto will avoid having bombs set to explode from a rock already destroyed from bullets
	    							goto STARTBIGROCKS;
    							
    							}					
					}
				}
			
			// Rock hasn't already been destroyed by bullets.  Check to see if the bombs are within proximity range
			for (counter2=0;counter2<MAX_BOMBS;counter2++)	
				if (bomb[counter2].state==ON || bomb[counter2].state==EXPLODING)
				{
					// Compute the distance the bomb is from the center of the rock
					distance=sqrt((bomb[counter2].x-bigrocks[counter].x) * (bomb[counter2].x-bigrocks[counter].x) + (bomb[counter2].y-bigrocks[counter].y) * (bomb[counter2].y-bigrocks[counter].y));
					
					// See if the distance is within the prox radius plus half the size of the rock
					if ( distance <= (PROX+(BIG_ROCK_SIZE>>1)))
					{
						// Check for direct hit or explosion timer
						if (distance <= (BIG_ROCK_SIZE>>1) || (proxtime[counter2] > PROX_TIMER))
						{
							if (bomb[counter2].state!=EXPLODING)
							{
								// place bomb explosion graphic.  This is JUST a graphic.
								explode1[Explode1QueueCounter].state=ON;
					    			explode1[Explode1QueueCounter].y=bomb[counter2].y;
    								explode1[Explode1QueueCounter].x=bomb[counter2].x;
    						
    								// set bomb property to exploding.  Note this is just a flag.  The bomb does not do anthing here
    								bomb[counter2].state=EXPLODING;
    						
    								// Update the Explode1 Queue
    								Explode1QueueCounter++;
    								if ((Explode1QueueCounter)==(MAX_BOMBS)) Explode1QueueCounter=0;
    							}

						}

						if (!proxtime[counter2]) // Bomb is in prox range.  Set timer if not already activated
						{
							// set timer
							proxtime[counter2]=1;
							// let bomb live longer so it can detonate
							bomb[counter2].anim_index=0;
						
						}
					}
				}
		}
	}
// This is exactly the same as for the big rocks, except when the rock is destroyed it makes 2 small rocks instead of 2 medium ones
counter=0;
STARTMEDIUMROCKS:
for (;counter<numberofmediumrocks;counter++)
	{
		// Move rock by delta v.  Note all rock position is relative to warbird
		mediumrocks[counter].x+=mediumrocks[counter].xv-warbird.xv;
		mediumrocks[counter].y+=mediumrocks[counter].yv-warbird.yv;
		// Flip rock through virtual subspace.  Note the player doesn't know the difference
		if (fabs(mediumrocks[counter].x)>=MAXX) mediumrocks[counter].x=-mediumrocks[counter].x;
		if (fabs(mediumrocks[counter].y)>=MAXY) mediumrocks[counter].y=-mediumrocks[counter].y;

		// If rock is close enough to be visible then display and animate it
		if (fabs(mediumrocks[counter].y)<((halfheight) + (MEDIUM_ROCK_SIZE>>1)) &&
		    fabs(mediumrocks[counter].x)<((halfwidth) + (MEDIUM_ROCK_SIZE>>1)))
		    {

		    	Animate_BOB(&mediumrocks[counter]);
		    	if (mediumrocks[counter].curr_frame==30) mediumrocks[counter].curr_frame=0;
				    	
		    	Draw_BOBXY(&mediumrocks[counter],lpddsback,(halfwidth)+mediumrocks[counter].x,(halfheight)+mediumrocks[counter].y);

		    	
		    	if ((fabs(mediumrocks[counter].x) <= (MEDIUM_ROCK_SIZE>>1) + 8) &&
		    	    (fabs(mediumrocks[counter].y) <= (MEDIUM_ROCK_SIZE>>1) + 8) && !playerdead)				    	
		    	{
				shipcollision=shipcollision | 2;
				    		
				// need a temporary holder to exchange values
				double tempa,tempb,tempc,tempd,warbirda,warbirdb,magnitude;

				// elastic collsion formula
										
				tempa=((WARBIRD_MASS-MEDIUM_ROCK_MASS) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * warbird.xv + ((MEDIUM_ROCK_MASS * 2.0) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * mediumrocks[counter].xv;
				tempb=((WARBIRD_MASS-MEDIUM_ROCK_MASS) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * warbird.yv + ((MEDIUM_ROCK_MASS * 2.0) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * mediumrocks[counter].yv;
				tempc=((WARBIRD_MASS*2.0) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * warbird.xv + ((MEDIUM_ROCK_MASS-WARBIRD_MASS) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * mediumrocks[counter].xv;
				tempd=((WARBIRD_MASS*2.0) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * warbird.yv + ((MEDIUM_ROCK_MASS-WARBIRD_MASS) / (WARBIRD_MASS+MEDIUM_ROCK_MASS)) * mediumrocks[counter].yv;
				
				// angle of refraction
				angle = arctangent(mediumrocks[counter].x,mediumrocks[counter].y);
								
				// warbird and rock temporary values are stored in order to compute damage				
				mediumrocks[counter].xv-=(fabs(cos(angle)))*(mediumrocks[counter].xv-tempc);
				mediumrocks[counter].yv-=(fabs(sin(angle)))*(mediumrocks[counter].yv-tempd);			
				warbirda=(fabs(cos(angle)))*(warbird.xv-tempa);
				warbirdb=(fabs(sin(angle)))*(warbird.yv-tempb);
								
				// Damage player ship
				// Collision strength is based on magnitude of the vector differences.
				// First, determine magnitude of collision
				magnitude=sqrt(warbirda*warbirda+warbirdb*warbirdb);
				
				// Now compute damage.  It's proportional to the maximum velocity that your ship is moved
				dmg=((magnitude/MAXSPEED)*CRASH_DAMAGE);
				Damage_Player((int)dmg);
				if (!playerdead) {warbird.xv-=warbirda;	warbird.yv-=warbirdb;}  // putting this line here lets explosion keep your momentum
				
				// Damage the rock too
				rockhp.medium[counter]-=(int)dmg;
				
				if (rockhp.medium[counter]<=0)  // Remove rock, make 2 small rocks
	    			{
    							
    					// Split rock into chunks
    					int counter3;
    					for (counter3=0;counter3<MEDIUM_ROCK_BREAK;counter3++) Create_Small_Rock(mediumrocks[counter].x,mediumrocks[counter].y);	
	    							
		    			// remove medium rock
	    				numberofmediumrocks--;
    					
    					if (counter!=numberofmediumrocks)
    					{		
    					// compact list by moving last element into destroyed element
    					memcpy(&mediumrocks[counter], &mediumrocks[numberofmediumrocks], sizeof(BOB));
	    				rockhp.medium[counter]=rockhp.medium[numberofmediumrocks];
	    				counter--;
	    				}
	    				continue;  // Go to next rock now.
    				}					
				
				
				// Move the rock a little away to prevent getting stuck.
				if (!playerdead)
				do
				{
				    	if (sin(angle)>=.69) mediumrocks[counter].y-=2;
				    	else if (sin(angle)<=-.69) mediumrocks[counter].y+=2;
				    	if (cos(angle)>=.69) mediumrocks[counter].x+=2;
				    	else if (cos(angle)<=-.69) mediumrocks[counter].x-=2;
				}
				
				// Perform another collision detection.  If still hit, move rock out of the way
				while ((fabs(mediumrocks[counter].x) <= (MEDIUM_ROCK_SIZE>>1) + 8) &&
					(fabs(mediumrocks[counter].y) <= (MEDIUM_ROCK_SIZE>>1) + 8));	
				    		
			}
			    	
			for (counter2=0;counter2<MAX_BULLETS;counter2++)	
				if (bullet[counter2].state==ON)
				{
					if (bullet[counter2].x >= mediumrocks[counter].x-(MEDIUM_ROCK_SIZE>>1) &&
					    bullet[counter2].x <= mediumrocks[counter].x+(MEDIUM_ROCK_SIZE>>1) &&
					    bullet[counter2].y >= mediumrocks[counter].y-(MEDIUM_ROCK_SIZE>>1) &&
					    bullet[counter2].y <= mediumrocks[counter].y+(MEDIUM_ROCK_SIZE>>1)-1)
					{
						
						// place bullet flash
						bulletflash[BulletflashQueueCounter].state=ON;
					    	bulletflash[BulletflashQueueCounter].y=bullet[counter2].y;
    						bulletflash[BulletflashQueueCounter].x=bullet[counter2].x;
    						
    						// remove bullet
    						bullet[counter2].state=OFF;
    						numberofbullets--; 					
    						
    						BulletflashQueueCounter++;
    						if ((BulletflashQueueCounter)==(MAX_BULLETS)) BulletflashQueueCounter=0;
    						
    						
						dmg=BULLET_DAMAGE;
						if (rand()%2) dmg-=rand() % (int)(BULLET_DAMAGE_RANGE*dmg);
						else dmg+=rand() % (int)(BULLET_DAMAGE_RANGE*dmg);
						rockhp.medium[counter]-=dmg;
						
    							if (rockhp.medium[counter]<=0)  // Remove rock, make 2 small rocks
	    						{
    							
    								// Split rock into chunks
    								int counter3;
    								for (counter3=0;counter3<MEDIUM_ROCK_BREAK;counter3++) Create_Small_Rock(mediumrocks[counter].x,mediumrocks[counter].y);	
	    							
	    							damage[DamageQueueCounter].state=ON;
						    		damage[DamageQueueCounter].y=mediumrocks[counter].y;
    								damage[DamageQueueCounter].x=mediumrocks[counter].x;
    								damage[DamageQueueCounter].yv=mediumrocks[counter].yv;
    								damage[DamageQueueCounter].xv=mediumrocks[counter].xv;
    						
   
    								DamageQueueCounter++;
    								
    								if ((DamageQueueCounter)==(MAX_MEDIUM_ROCKS)) DamageQueueCounter=0;
	    							
	    							// remove medium rock
    								numberofmediumrocks--;
    							
    								// compact list by moving last element into destroyed element
    								if (counter!=numberofmediumrocks)
    								{
    								memcpy(&mediumrocks[counter], &mediumrocks[numberofmediumrocks], sizeof(BOB));
	    							rockhp.medium[counter]=rockhp.medium[numberofmediumrocks];
	    							}
	    							
	    							score+=MEDIUM_ROCK_POINTS;
	    							
	    							counter2=MAX_BULLETS; // break out of the loop
	    							
								// Play rock explosion sound
	    							Play_Sound(explode1_id);
	    							
	    							//if (Explode1QueueCounter==MAX_EXPLOSION_SOUNDS) Explode1QueueCounter=0;
	    							goto STARTMEDIUMROCKS;
    							}					
					}
				}
			
			// if rock hasn't already been destroyed by bullets check for bomb damage						
			for (counter2=0;counter2<MAX_BOMBS;counter2++)	
				if (bomb[counter2].state==ON || bomb[counter2].state==EXPLODING)
				{
					distance=sqrt((bomb[counter2].x-mediumrocks[counter].x) * (bomb[counter2].x-mediumrocks[counter].x) + (bomb[counter2].y-mediumrocks[counter].y) * (bomb[counter2].y-mediumrocks[counter].y));
										
					if ( distance <= (PROX+(MEDIUM_ROCK_SIZE>>1)))
					{
						// Check for direct hit or explosion timer
						
						if (distance <= (MEDIUM_ROCK_SIZE>>1) || (proxtime[counter2] > PROX_TIMER))
						{
							if (bomb[counter2].state!=EXPLODING)
							{
								// place bomb explosion
								explode1[Explode1QueueCounter].state=ON;
					    			explode1[Explode1QueueCounter].y=bomb[counter2].y;
    								explode1[Explode1QueueCounter].x=bomb[counter2].x;
    						
    								// remove bomb
    								bomb[counter2].state=EXPLODING;
    						
    								Explode1QueueCounter++;
    								if ((Explode1QueueCounter)==(MAX_BOMBS)) Explode1QueueCounter=0;
    							}

						}

						if (!proxtime[counter2]) // Bomb is in prox range.  Set timer if not already activated
						{
							// set timer
							proxtime[counter2]=1;
							// let bomb live longer so it can detonate
							bomb[counter2].anim_index=0;
						
						}
					}
				}
		}
	}
	counter=0;
	STARTSMALLROCKS:
	for (;counter<numberofsmallrocks;counter++)
	{
		// Move rock by delta v.  Note all rock position is relative to warbird
		smallrocks[counter].x+=smallrocks[counter].xv-warbird.xv;
		smallrocks[counter].y+=smallrocks[counter].yv-warbird.yv;
		// Flip rock through virtual subspace.  Note the player doesn't know the difference
		if (fabs(smallrocks[counter].x)>=MAXX) smallrocks[counter].x=-smallrocks[counter].x;
		if (fabs(smallrocks[counter].y)>=MAXY) smallrocks[counter].y=-smallrocks[counter].y;
			
		// If rock is close enough to be visible then display and animate it
		if (fabs(smallrocks[counter].y)<((halfheight) + (SMALL_ROCK_SIZE>>1)) &&
		    fabs(smallrocks[counter].x)<((halfwidth) + (SMALL_ROCK_SIZE>>1)))
		    {
	   	
		    	// smallrocks[counter].curr_frame++;
		    	Animate_BOB(&smallrocks[counter]);
		    	if (smallrocks[counter].curr_frame==30) smallrocks[counter].curr_frame=0;
				    	
		    	Draw_BOBXY(&smallrocks[counter],lpddsback,(halfwidth)+smallrocks[counter].x,(halfheight)+smallrocks[counter].y);

		    	if ((fabs(smallrocks[counter].x) <= (SMALL_ROCK_SIZE>>1) + 8) &&
		    	    (fabs(smallrocks[counter].y) <= (SMALL_ROCK_SIZE>>1) + 8) && !playerdead)				    	
		    	{
				shipcollision=shipcollision | 1;
				    		
				// need a temporary holder to exchange values
				double tempa,tempb,tempc,tempd,warbirda,warbirdb,magnitude;


				// elastic collsion formula					
				tempa=((WARBIRD_MASS-SMALL_ROCK_MASS) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * warbird.xv + ((SMALL_ROCK_MASS * 2.0) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * smallrocks[counter].xv;
				tempb=((WARBIRD_MASS-SMALL_ROCK_MASS) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * warbird.yv + ((SMALL_ROCK_MASS * 2.0) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * smallrocks[counter].yv;
				tempc=((WARBIRD_MASS*2.0) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * warbird.xv + ((SMALL_ROCK_MASS-WARBIRD_MASS) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * smallrocks[counter].xv;
				tempd=((WARBIRD_MASS*2.0) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * warbird.yv + ((SMALL_ROCK_MASS-WARBIRD_MASS) / (WARBIRD_MASS+SMALL_ROCK_MASS)) * smallrocks[counter].yv;
				
				// angle of refraction
				angle = arctangent(smallrocks[counter].x,smallrocks[counter].y);
								
				// warbird and rock temporary values are stored in order to compute damage				
				smallrocks[counter].xv-=(fabs(cos(angle)))*(smallrocks[counter].xv-tempc);
				smallrocks[counter].yv-=(fabs(sin(angle)))*(smallrocks[counter].yv-tempd);			
				warbirda=(fabs(cos(angle)))*(warbird.xv-tempa);
				warbirdb=(fabs(sin(angle)))*(warbird.yv-tempb);
								
				// Damage player ship
				// Collision strength is based on magnitude of the vector differences.
				// First, determine magnitude of collision
				magnitude=sqrt(warbirda*warbirda+warbirdb*warbirdb);
				// Now compute damage.  It's proportional to the maximum velocity that your ship is moved
				dmg=(magnitude/MAXSPEED)*CRASH_DAMAGE;
				
				Damage_Player((int)dmg);
				if (!playerdead) {warbird.xv-=warbirda;	warbird.yv-=warbirdb;}  // putting this line here lets explosion keep your momentum
				
				
				// Damage the rock too
				rockhp.small[counter]-=(int)dmg;
				
				if (rockhp.small[counter]<=0)  // Remove rock, make 2 small rocks
	    			{
    							
					damage[DamageQueueCounter].state=ON;
					damage[DamageQueueCounter].y=smallrocks[counter].y;
    					damage[DamageQueueCounter].x=smallrocks[counter].x;
    					
    					// yv is y velocity.  xv is x velocity
    					damage[DamageQueueCounter].yv=smallrocks[counter].yv;
    					damage[DamageQueueCounter].xv=smallrocks[counter].xv;
    						
    					// remove small rock
    					numberofsmallrocks--;
    					
    					if (counter!=numberofsmallrocks)
    					{
    					// compact list by moving last element into destroyed element
    					memcpy(&smallrocks[counter], &smallrocks[numberofsmallrocks], sizeof(BOB));     
    					rockhp.small[counter]=rockhp.small[numberofsmallrocks];
    					counter--;
    					}
    						
    					DamageQueueCounter++;
    								
    					if ((DamageQueueCounter)==(MAX_SMALL_ROCKS)) DamageQueueCounter=0;
    							
    					continue;  // Go to next rock
    				}	
				
				// Move the rock a little away to prevent getting stuck.
				if (!playerdead)
				do
				{
				    	if (sin(angle)>=.69) smallrocks[counter].y-=2;
				    	else if (sin(angle)<=-.69) smallrocks[counter].y+=2;
				    	if (cos(angle)>=.69) smallrocks[counter].x+=2;
				    	else if (cos(angle)<=-.69) smallrocks[counter].x-=2;
				}
				
				// Perform another collision detection.  If still hit, move rock out of the way
				while ((fabs(smallrocks[counter].x) <= (SMALL_ROCK_SIZE>>1) + 8) &&
					(fabs(smallrocks[counter].y) <= (SMALL_ROCK_SIZE>>1) + 8));	
				    		
			}
			    	
			for (counter2=0;counter2<MAX_BULLETS;counter2++)	
				if (bullet[counter2].state==ON)
				{
					if (bullet[counter2].x >= smallrocks[counter].x-(SMALL_ROCK_SIZE>>1) &&
					    bullet[counter2].x <= smallrocks[counter].x+(SMALL_ROCK_SIZE>>1) &&
					    bullet[counter2].y >= smallrocks[counter].y-(SMALL_ROCK_SIZE>>1) &&
					    bullet[counter2].y <= smallrocks[counter].y+(SMALL_ROCK_SIZE>>1)-1)
					{
						
						// place bullet flash
						bulletflash[BulletflashQueueCounter].state=ON;
					    	bulletflash[BulletflashQueueCounter].y=bullet[counter2].y;
    						bulletflash[BulletflashQueueCounter].x=bullet[counter2].x;
    						
    						// remove bullet
    						bullet[counter2].state=OFF;
    						numberofbullets--; 					
    						
    						BulletflashQueueCounter++;
    						if ((BulletflashQueueCounter)==(MAX_BULLETS)) BulletflashQueueCounter=0;
    						
    						
						dmg=BULLET_DAMAGE;
						if (rand()%2) dmg-=rand() % (int)(BULLET_DAMAGE_RANGE*dmg);
						else dmg+=rand() % (int)(BULLET_DAMAGE_RANGE*dmg);
						rockhp.small[counter]-=dmg;
						
    						if (rockhp.small[counter]<=0)  // Remove rock, set explosion graphic
    						{
    								
							damage[DamageQueueCounter].state=ON;
							damage[DamageQueueCounter].y=smallrocks[counter].y;
    							damage[DamageQueueCounter].x=smallrocks[counter].x;
    							damage[DamageQueueCounter].yv=smallrocks[counter].yv;
    							damage[DamageQueueCounter].xv=smallrocks[counter].xv;
    						
    						
    							// remove small rock
    							numberofsmallrocks--;
    							
    							// compact list by moving last element into destroyed element
    							if (counter!=numberofsmallrocks)
    							{
    							memcpy(&smallrocks[counter], &smallrocks[numberofsmallrocks], sizeof(BOB));     
    							rockhp.small[counter]=rockhp.small[numberofsmallrocks];
    							}
    						   						
    						
    							DamageQueueCounter++;
    							
    							if ((DamageQueueCounter)==(MAX_SMALL_ROCKS)) DamageQueueCounter=0;
    							
    							score+=SMALL_ROCK_POINTS;
    							
    							counter2=MAX_BULLETS; // break out of the loop
    							
    							// Play rock explosion sound
	    						Play_Sound(explode1_id);
	    						//if (Explode1QueueCounter==MAX_EXPLOSION_SOUNDS) Explode1QueueCounter=0;
	    						goto STARTSMALLROCKS;
    						}						
					}
				}
			
			// if rock hasn't already been destroyed by bullets check to set bomb explosions					
			for (counter2=0;counter2<MAX_BOMBS;counter2++)	
				if (bomb[counter2].state==ON || bomb[counter2].state==EXPLODING)
				{
					distance=sqrt((bomb[counter2].x-smallrocks[counter].x) * (bomb[counter2].x-smallrocks[counter].x) + (bomb[counter2].y-smallrocks[counter].y) * (bomb[counter2].y-smallrocks[counter].y));
										
					if ( distance <= (PROX+(SMALL_ROCK_SIZE>>1)))
					{
						// Check for direct hit or explosion timer
						
						if (distance <= (SMALL_ROCK_SIZE>>1) || (proxtime[counter2] > PROX_TIMER))
						{
							if (bomb[counter2].state!=EXPLODING)
							{
								// place bomb explosion graphic
								explode1[Explode1QueueCounter].state=ON;
					    			explode1[Explode1QueueCounter].y=bomb[counter2].y;
    								explode1[Explode1QueueCounter].x=bomb[counter2].x;
    						
    								// Set bomb to explode
    								bomb[counter2].state=EXPLODING;
    						
    								Explode1QueueCounter++;
    								if ((Explode1QueueCounter)==(MAX_BOMBS)) Explode1QueueCounter=0;
    							}

						}

						if (!proxtime[counter2]) // Bomb is in prox range.  Set timer if not already activated
						{
							// set timer
							proxtime[counter2]=1;
							// let bomb live longer so it can detonate
							bomb[counter2].anim_index=0;
						
						}
					}
				}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////

void Draw_Stars(void)
{
	// Lock the back surface for writing
	DD_Lock_Back_Surface();
	
	for (counter=0;counter<numberofstars;counter++)
		{
				// Note all rock position is relative to warbird
				// stars[counter].x-=warbird.xv/PARALLAX_RATE;
				// stars[counter].y-=warbird.yv/PARALLAX_RATE;
				stars[counter].x-=warbird.xv;
				stars[counter].y-=warbird.yv;
				// Flip stars through virtual subspace.  Note the player doesn't know the difference unless the game area is smaller than the screen resolution
				// which it shouldn't be...
				if (fabs(stars[counter].x)>=MAXX) stars[counter].x=-stars[counter].x;
				if (fabs(stars[counter].y)>=MAXY) stars[counter].y=-stars[counter].y;
				
				// If star is close enough to be visible then display it
				if (fabs(stars[counter].y)<(halfheight) &&
				    fabs(stars[counter].x)<(halfwidth))
				    {
					// Draw a white dot unless in radar box
					if (!(
					(halfwidth+(int)stars[counter].x > width-11-RADAR_SIZE) &&
					(halfwidth+(int)stars[counter].x < width-10) &&
					(halfheight+(int)stars[counter].y > height-11-RADAR_SIZE) &&
					(halfheight+(int)stars[counter].y < height-10)
					))
				    	back_buffer[halfwidth+(int)stars[counter].x + (halfheight+(int)stars[counter].y)*back_lpitch] = 255;
				    }
				
		}
		
	// Unlock the back surface
	DD_Unlock_Back_Surface();
}

///////////////////////////////////////////////////////////////////

void Draw_Exhaust(void)
// This function is optimized to assume thrust in pairs started at the same time
{
	for (counter=0;counter<(EXHAUST_BMP_FRAMES<<1);counter+=2)
		if (exhaust[counter].state==ON)
		{
				
				if (exhaust[counter].curr_frame)  // Don't move the first frame
				{
					// Notice the exhaust has a velocity of its own.  Otherwise when flying backwards and hitting reverse you have a long exhaust trail coming
					// from your nose.
					exhaust[counter].x-=warbird.xv+exhaust[counter].xv;
					exhaust[counter].y-=warbird.yv+exhaust[counter].yv;
					
					// The second exhaust animation is always one element higher than the last
					exhaust[counter+1].x-=warbird.xv+exhaust[counter+1].xv;
					exhaust[counter+1].y-=warbird.yv+exhaust[counter+1].yv;
				}

				// Draw both exhaust puffs at whatever animation state it's currently in
			    	Draw_BOBXY(&exhaust[counter],lpddsback,(halfwidth)+exhaust[counter].x,(halfheight)+exhaust[counter].y);
			    	Draw_BOBXY(&exhaust[counter+1],lpddsback,(halfwidth)+exhaust[counter+1].x,(halfheight)+exhaust[counter+1].y);
			    	
			    	// Go to the next frame of the exhaust animation
			    	exhaust[counter].curr_frame++;
			    	exhaust[counter+1].curr_frame++;
			    	
			    	// See if the exaust has reached the last frame
			    	if (exhaust[counter].curr_frame==EXHAUST_BMP_FRAMES)
			    	{
			    		// The exhaust graphic has reached the last frame.  Turn it off through the state variable.  Reset the animation sequence to 0
			    		exhaust[counter].curr_frame=0;
			    		exhaust[counter].state=OFF;
			    		exhaust[counter+1].curr_frame=0;
			    		exhaust[counter+1].state=OFF;
			    	}	
				
		}
}

//////////////////////////////////////////////////////////////////////

void Draw_Energy_Bar(void)
{
	int length;  // length of energy bar
	int color;  // color of energy bar
	

	// Lock the back surface for writing
  	DD_Lock_Back_Surface();

	// If you have more than half energy use the energybara bitmap, which doesn't have the red emergency light lit
   	if (energy > (MAX_ENERGY>>1)) Draw_Bitmap(&energybara,back_buffer,back_lpitch,1);
	else Draw_Bitmap(&energybarb,back_buffer,back_lpitch,1);  // Otherwise use energybarb which does
	
	// Determine the length of the energy bar.  This is based on simply the proportion of your energy to the maximum energy
	length=(float)(halfwidth>>1)*((float)energy/(float)MAX_ENERGY);
	
	// Draw the left and right lines which go over the energy bar itself.  They are both the same length.
	Draw_Line(halfwidth-(halfwidth>>1)-10,ENERGY_BAR_DOWNSET+10,halfwidth-10,ENERGY_BAR_DOWNSET+10,184,back_buffer,back_lpitch);
	Draw_Line(halfwidth+(halfwidth>>1)+10,ENERGY_BAR_DOWNSET+10,halfwidth+10,ENERGY_BAR_DOWNSET+10,184,back_buffer,back_lpitch);
	
	// Unlock the back surface for later display
	DD_Unlock_Back_Surface();
	
	// If you have less than 1/4 energy left display your energy numerically next to your ship
	if (energy<(MAX_ENERGY>>2))
		{
			color=41;  // Red palette number
			itoa(energy,buffer,10);
			Draw_Text_GDI(buffer,halfwidth+16,halfheight+16,color,lpddsback);
		}
	else if (energy<(MAX_ENERGY>>1))  // Less than 1/2 energy
		{
			itoa(energy,buffer,10);
			color=109;  // Yellow palette number
			Draw_Text_GDI(buffer,halfwidth+16,halfheight+16,color,lpddsback);
		}
	else color=184;  // Blue palette number
	
	// Draw the energy indicator rectangles under the bars using the color determined above
	Draw_Rectangle(halfwidth-11-length,ENERGY_BAR_DOWNSET+10,halfwidth-9,ENERGY_BAR_DOWNSET+18,color,lpddsback);
	Draw_Rectangle(halfwidth+9,ENERGY_BAR_DOWNSET+10,halfwidth+11+length,ENERGY_BAR_DOWNSET+18,color,lpddsback);	

}

///////////////////////////////////////////////////////////////////////

void Draw_Bullets(void)
{
	
	// Lock the back surface for writing
	DD_Lock_Back_Surface();
	
	// Cycle through the bullets and display each active one (with the state flag == ON)
	for (counter=0;counter<MAX_BULLETS;counter++)	
		if (bullet[counter].state==ON)
			{
				// Check if the bullet has expired.
				if (bullet[counter].lifetime==BULLET_LIFETIME)
					{
						// Bullet has expired.  Turn it off
						bullet[counter].state=OFF;
						
						// Decrease the total number of bullets
						numberofbullets--;
					}
				else
				{
					// Increase the bullet lifetime used to determine if it's expired or not
					bullet[counter].lifetime++;
					
					// Move bullet by delta v.  Note all bullet position is relative to warbird
					bullet[counter].x+=bullet[counter].xv-warbird.xv;
					bullet[counter].y+=bullet[counter].yv-warbird.yv;
					
					// Don't flip bullet because you have the illusion of unlimited space
					// if (abs(bullet[counter].x)>=MAXX) bullet[counter].x=-bullet[counter].x;
					// if (abs(bullet[counter].y)>=MAXY) bullet[counter].y=-bullet[counter].y;
				
					// If bullet is close enough to be visible then display and animate it
					if (fabs(bullet[counter].y)<((halfheight)) &&
				    	    fabs(bullet[counter].x)<((halfwidth)))
				    	{
				    		// Draw 5 pixels in a cross pattern to display the bullet			    	
					    	back_buffer[halfwidth+(int)bullet[counter].x -1 + (halfheight+(int)bullet[counter].y)*back_lpitch] = bullet[counter].color;
					    	back_buffer[halfwidth+(int)bullet[counter].x + (halfheight+(int)bullet[counter].y)*back_lpitch] = bullet[counter].color;
					    	back_buffer[halfwidth+(int)bullet[counter].x +1 + (halfheight+(int)bullet[counter].y)*back_lpitch] = bullet[counter].color;
					    	back_buffer[halfwidth+(int)bullet[counter].x + (halfheight+(int)bullet[counter].y+1)*back_lpitch] = bullet[counter].color;
					    	back_buffer[halfwidth+(int)bullet[counter].x + (halfheight+(int)bullet[counter].y-1)*back_lpitch] = bullet[counter].color;
					    	
				    		// Make bullet glow more or less.  I'm too lazy to actually pick colors
				    		bullet[counter].color++;
				    	
				    		// Cycle through the defined palette colors
				    		if (bullet[counter].color>UPPER_PALETTE_BULLET_COLOR) bullet[counter].color=LOWER_PALETTE_BULLET_COLOR;
				    	}
				}
				
			}
	
	// Unlock the back surface
	DD_Unlock_Back_Surface();			
			
}

/////////////////////////////////////////////////////////////////////////////

void Draw_Bombs(void)
{
	int counter2, counter3;
	double dmg;
	int idmg;
	double distance;
	
	// These are used to prevent newly formed rocks from split asteroids from being immediately destroyed from the bomb which killed the 'parent'
	int initialmediumrocks=numberofmediumrocks;
	int initialsmallrocks=numberofsmallrocks;
	
	// These are flags used to determine if the explosion sound is already playing.  Without it, if you destroy 10 rocks with 1 bomb you'd get 10 sounds blasting at the same time
	int sound1on=OFF,sound2on=OFF;

	for (counter=0;counter<MAX_BOMBS;counter++)	
	{
		// Remove exploded bombs from Move_Rocks() function
		if (bomb[counter].state==EXPLODING)
		{
			// Get distance from player
			distance=sqrt(bomb[counter].x * bomb[counter].x + bomb[counter].y * bomb[counter].y);

			if (distance<PROX) // pbomb
			{
				
				dmg=( ( (PROX) -distance) / (PROX)) * ((double) BOMB_DAMAGE);  // Damage is proportional to distance
				
				// This circumvented one of the hardest bugs to find in the code.  Roundoff error when converting double to an int for use by the modulus sometimes
				// gave a value of 0 for dmg.  MOD 0 is undefined and resulted in lockups when a bomb would detonate at exactly maximum range.(defined by PROX)
				idmg=(int)(BOMB_DAMAGE_RANGE*dmg);
				
				// If damage is done...
				if (idmg)
				{	
					// Adjust the damage by + or - a random percent of the damage modifier
					if (rand()%2) dmg-=rand() % idmg;
					else dmg+=rand() % idmg;
					
					// Apply the damage to the player.  Yes, you can kill yourself by Pboming.
					Damage_Player(dmg);
				}
			}
			
			// CYCLE THROUGH EACH OF THE BIG ROCKS AND APPLY BOMB DAMAGE	
			for (counter2=0;counter2<numberofbigrocks;counter2++)
			{
				// Calculate the distance from the bomb to the rock
				distance=sqrt((bomb[counter].x-bigrocks[counter2].x) * (bomb[counter].x-bigrocks[counter2].x) + (bomb[counter].y-bigrocks[counter2].y) * (bomb[counter].y-bigrocks[counter2].y));
				
				// This code is the same as the detonation activation code found in Move_Rocks.  At first I had it there for efficiency but when a bomb would blow up the damage would
				// only be applied to that rock, rocks checked further down the loop, and smaller rocks whose code happened to be located later down.  The resultant bug
				// would be when you bombed a big rock next to a small one they would both blow but if you shot a small one next to a big one only the small one would blow.
				//  If you shot rocks of equal size both or only one may blow, depending on each rock's arbitrary index in the array
				if ( distance < (PROX+(BIG_ROCK_SIZE>>1)))
				{
					distance-=(BIG_ROCK_SIZE>>1); // Use distance from surface instead of distance from center
					
					// If a very fast moving bomb detonated inside the surface of the rock just due to high pixel jumps distance could possibly be under 0
					if (distance<0.0) distance=0.0;
		
					// Damage is proportional to distance
					dmg=(((PROX)-distance)/(PROX)) * ((double) BOMB_DAMAGE);
					
					// Bug fix as described above
					idmg=(int)(BOMB_DAMAGE_RANGE*dmg);
					
					if (!idmg) idmg=1;
					if (rand()%2) dmg-=rand() % idmg;
					else dmg+=rand() % idmg;
					
					// Take life from rock
					rockhp.big[counter2]-=dmg;
					
					// Check if rock destroyed
					if (rockhp.big[counter2]<=0)  // Remove rock, make 2 small rocks
    					{
    						
						// Split rock into chunks
						for (counter3=0;counter3<BIG_ROCK_BREAK;counter3++) Create_Medium_Rock(bigrocks[counter2].x,bigrocks[counter2].y);	
	    					// remove big rock
    						numberofbigrocks--;
    						// compact list by moving last element into destroyed element
    						if (counter2!=numberofbigrocks)
    						{
    							memcpy(&bigrocks[counter2], &bigrocks[numberofbigrocks], sizeof(BOB));
	    						rockhp.big[counter2]=rockhp.big[numberofbigrocks];
	    						counter2--;
	    					}
	    					
    						score+=BIG_ROCK_POINTS;
						// Play rock explosion sound as long as the sound isn't already playing
    						if (!sound1on) {Play_Sound(explode1_id); sound1on=1;}
    					}
    					else
    					{
    					// Play bomb explosion sound as long as the sound isn't already playing
	    				if (!sound2on) {Play_Sound(explode0_id); sound2on=1;}
	    				}
	    			}
	    		}
	    					
			// CYCLE THROUGH EACH OF THE MEDIUM ROCKS AND APPLY DAMAGE	
			for (counter2=0;counter2<initialmediumrocks;counter2++)
			{
				distance=sqrt((bomb[counter].x-mediumrocks[counter2].x) * (bomb[counter].x-mediumrocks[counter2].x) + (bomb[counter].y-mediumrocks[counter2].y) * (bomb[counter].y-mediumrocks[counter2].y));
				if ( distance < (PROX+(MEDIUM_ROCK_SIZE>>1)))
				{
					distance-=(MEDIUM_ROCK_SIZE>>1); // Use distance from surface instead of distance from center
					if (distance<0.0) distance=0.0;
					
					// Same comments as above with big rocks
					dmg=(((PROX)-distance)/(PROX)) * ((double) BOMB_DAMAGE);
					idmg=(int)(BOMB_DAMAGE_RANGE*dmg);
					if (!idmg) idmg=1;
					if (rand()%2) dmg-=rand() % idmg;
					else dmg+=rand() % idmg;
					rockhp.medium[counter2]-=dmg;
					if (rockhp.medium[counter2]<=0)  // Remove rock, make 2 small rocks
    					{
    						damage[DamageQueueCounter].state=ON;
						damage[DamageQueueCounter].y=mediumrocks[counter2].y;
    						damage[DamageQueueCounter].x=mediumrocks[counter2].x;
    						damage[DamageQueueCounter].yv=mediumrocks[counter2].yv;
    						damage[DamageQueueCounter].xv=mediumrocks[counter2].xv;
						DamageQueueCounter++;
    						if ((DamageQueueCounter)==(MAX_MEDIUM_ROCKS)) DamageQueueCounter=0;  
						// Split rock into chunks
						for (counter3=0;counter3<MEDIUM_ROCK_BREAK;counter3++) Create_Small_Rock(mediumrocks[counter2].x,mediumrocks[counter2].y);	
	    					// remove medium rock
    						numberofmediumrocks--;
    						// compact list by moving last element into destroyed element
    						if (counter2!=numberofmediumrocks)
    						{
    							memcpy(&mediumrocks[counter2], &mediumrocks[numberofmediumrocks], sizeof(BOB));
	    						rockhp.medium[counter2]=rockhp.medium[numberofmediumrocks];
	    						
	    						// If initialmediumrocks!=numberofmediumrocks then new rocks were formed from a splitting 'parent'  I don't want to immediately check
	    						// the newly formed rock for damage, so don't perform another loop with the same value of counter2, which is what subtracting
	    						// one from it would do
	    						if (initialmediumrocks!=numberofmediumrocks) counter2--;
	    					}
    						score+=MEDIUM_ROCK_POINTS;
						// Play rock explosion sound
						if (!sound1on) {Play_Sound(explode1_id); sound1on=1;}
    					}
    					else
    					{
    					// Play bomb explosion sound
	    				if (!sound2on) {Play_Sound(explode0_id); sound2on=1;}
	    				}
	    			}
	    		}
	    					
			// CYCLE THROUGH EACH OF THE SMALL ROCKS AND APPLY DAMAGE	
			for (counter2=0;counter2<initialsmallrocks;counter2++)
			{
				distance=sqrt((bomb[counter].x-smallrocks[counter2].x) * (bomb[counter].x-smallrocks[counter2].x) + (bomb[counter].y-smallrocks[counter2].y) * (bomb[counter].y-smallrocks[counter2].y));
				if ( distance < (PROX+(SMALL_ROCK_SIZE>>1)))
				{
					distance-=(SMALL_ROCK_SIZE>>1); // Use distance from surface instead of distance from center
					if (distance<0.0) distance=0.0;
					
					// Same comments as with the big rocks
					dmg=(((PROX)-distance)/(PROX)) * ((double) BOMB_DAMAGE);
					idmg=(int)(BOMB_DAMAGE_RANGE*dmg);
					if (!idmg) idmg=1;
					if (rand()%2) dmg-=rand() % idmg;
					else dmg+=rand() % idmg;
					
					rockhp.small[counter2]-=dmg;
					if (rockhp.small[counter2]<=0)
    					{
    						
    						// damage is simply the name of the smoke puff object that displays and animates when the small rocks are destroyed.  The name just comes from the
    						// filename which in subspace was the puff displayed when your ship takes damage
						damage[DamageQueueCounter].state=ON;
						damage[DamageQueueCounter].y=smallrocks[counter2].y;
    						damage[DamageQueueCounter].x=smallrocks[counter2].x;
    						damage[DamageQueueCounter].yv=smallrocks[counter2].yv;
    						damage[DamageQueueCounter].xv=smallrocks[counter2].xv;
    						
    						// Update counter for this graphic
						DamageQueueCounter++;
    						if ((DamageQueueCounter)==(MAX_SMALL_ROCKS)) DamageQueueCounter=0;    						
    						
	    					// remove small rock
    						numberofsmallrocks--;
    						
    						// compact list by moving last element into destroyed element
    						if (counter2!=numberofsmallrocks)
    						{
    							memcpy(&smallrocks[counter2], &smallrocks[numberofsmallrocks], sizeof(BOB));
	    						rockhp.small[counter2]=rockhp.small[numberofsmallrocks];
	    						
	    						// If initialsmallrocks!=numberofsmallrocks then new rocks were formed from a splitting 'parent'  I don't want to immediately check
	    						// the newly formed rock for damage, so don't perform another loop with the same value of counter2, which is what subtracting
	    						// one from it would do
	    						if (initialsmallrocks!=numberofsmallrocks) counter2--;
	    					}
    						score+=SMALL_ROCK_POINTS;
						// Play rock explosion sound
    						if (!sound1on) {Play_Sound(explode1_id); sound1on=1;}
    					}
    					else
    					{
    					// Play bomb explosion sound
	    				if (!sound2on) {Play_Sound(explode0_id); sound2on=1;}
	    				}
	    			}
	    		}				
				
			bomb[counter].state=OFF;
			numberofbombs--;
		}
		//  All exploding bombs processed.  Now process bombs which aren't exploding
		else if (bomb[counter].state==ON)
			{
				//  Remove expired bombs.  anim_index is nothing more than a counter which holds how long the bomb has been active.  Since I animate bombs manually the variable
				//  was free.  Don't try to use the animate function with the bomb object unless a new variable is made to take the place of it
				if (bomb[counter].anim_index==BOMB_LIFETIME)
				{
					bomb[counter].state=OFF;
					numberofbombs--;
				}
				else
				{
					// Bomb didn't reach lifetime.  Update its age with the anim_index variable
					bomb[counter].anim_index++;
				
					if (proxtime[counter])
					{
						// If prox is activiated then update the timer.which counts down towards detonation
						proxtime[counter]++;
						// Timer could go beyond limit and not detonate if the trigger rock was destroyed or the bomb flew out of range.  If so, reset timer.
						if (proxtime[counter] > PROX_TIMER+1) proxtime[counter]=0;
					}
					
				// Move bomb by delta v.  Note all bomb position is relative to warbird
				bomb[counter].x+=bomb[counter].xv-warbird.xv;
				bomb[counter].y+=bomb[counter].yv-warbird.yv;
				
				// Don't flip bomb because you have the illusion of unlimited space
				// if (abs(bomb[counter].x)>=MAXX) bomb[counter].x=-bomb[counter].x;
				// if (abs(bomb[counter].y)>=MAXY) bomb[counter].y=-bomb[counter].y;
				
				// If bomb is close enough to be visible then display and animate it
				if (fabs(bomb[counter].y)<((halfheight)+3) &&
				    fabs(bomb[counter].x)<((halfwidth)+3))
				    {
				    	// anim_index is used to hold bomb lifetime.  Don't use animate function.  curr_frame is what actually controls the animation frame
				    	bomb[counter].curr_frame++;
				    	
				    	// Loop curr_frame so the animation starts over, if needed
				    	if (bomb[counter].curr_frame==BOMB_BMP_FRAMES) bomb[counter].curr_frame=0;
				   
				   	// Draw the bomb.  To the backbuffer of course
				    	Draw_BOBXY(&bomb[counter],lpddsback,(halfwidth)+bomb[counter].x,(halfheight)+bomb[counter].y);

				    }
				}
				
			}
		}
}

////////////////////////////////////////////////////////////////////////

void Draw_Radar(void)
{
	int x,y;

	// Lock the back surface
	DD_Lock_Back_Surface();
	
	// The 10 is the offset in pixels from the bottom and right side of the screen.  11 is 10 plus 1 pixel so the inner box is the actual RADAR_SIZE
	// Draw bottom line,from right to left
	Draw_Line(width-10,height-10,width-11-RADAR_SIZE,height-10,255,back_buffer,back_lpitch);
	// Draw left line, from bottom to top
	Draw_Line(width-11-RADAR_SIZE,height-10,width-11-RADAR_SIZE,height-11-RADAR_SIZE,255,back_buffer,back_lpitch);
	// Draw top line, from left to right
	Draw_Line(width-11-RADAR_SIZE,height-11-RADAR_SIZE,width-10,height-11-RADAR_SIZE,255,back_buffer,back_lpitch);
	// Draw right line, from top to bottom
	Draw_Line(width-10,height-11-RADAR_SIZE,width-10,height-10,255,back_buffer,back_lpitch);

// Draw the colored pixels indicating big rocks on the radar
// Notice I use MAXX and MAXY, the dimensions of the subspace.  This is because the radar displays the entire subspace, not just the visible area
for (counter=0;counter<numberofbigrocks;counter++)	
{
	x=(((MAXX+bigrocks[counter].x) / (float) (MAXX<<1) ) * RADAR_SIZE) + width-10-RADAR_SIZE;
	y=(((MAXY+bigrocks[counter].y) / (float) (MAXY<<1) ) * RADAR_SIZE) + height-10-RADAR_SIZE;
	back_buffer[x+y*back_lpitch]= BIG_ROCK_RADAR_COLOR;
}

// Draw the colored pixels indicating medium rocks on the radar
for (counter=0;counter<numberofmediumrocks;counter++)
{
	x=(((MAXX+mediumrocks[counter].x) / (float) (MAXX<<1) ) * RADAR_SIZE) + width-10-RADAR_SIZE;
	y=(((MAXY+mediumrocks[counter].y) / (float) (MAXY<<1) ) * RADAR_SIZE) + height-10-RADAR_SIZE;
	back_buffer[x+y*back_lpitch]= MEDIUM_ROCK_RADAR_COLOR;	
}

// Draw the colored pixels indicating small rocks on the radar
for (counter=0;counter<numberofsmallrocks;counter++)	
{
	x=(((MAXX+smallrocks[counter].x) / (float) (MAXX<<1) ) * RADAR_SIZE) + width-10-RADAR_SIZE;
	y=(((MAXY+smallrocks[counter].y) / (float) (MAXY<<1) ) * RADAR_SIZE) + height-10-RADAR_SIZE;
	back_buffer[x+y*back_lpitch]= SMALL_ROCK_RADAR_COLOR;
}

// Determine the center of the radar
x=width-10-(RADAR_SIZE/2);
y=height-10-(RADAR_SIZE/2);

// Draw a dot representing the ship there
back_buffer[x+y*back_lpitch]= SHIP_RADAR_COLOR;

// Unlock the back surface
DD_Unlock_Back_Surface();
}

/////////////////////////////////////////////////////////////////////////////

double arctangent(double x, double y)
{
// This doesn't actually return the arctangent.  It returns the angle in radians to a point x,y from the coordinate axis using the arctangent.  It works in all quadrants
	double angle;

	if (x==0.0)
	{
		if (y>0.0) angle=3.0*M_PI/2.0;
		else angle=M_PI/2.0;
	}
	else
	{
   		angle = atan(y/x);
		if (y>0.0)
		{
			if (x>0.0) angle=2.0*M_PI-angle;
			else angle=M_PI-angle;
		}
		else
		{
			if (x>0.0) angle=-angle;
			else angle=M_PI-angle;
		}
				    		
	}
	return angle;
}


///////////////////////////////////////////////////////////////////

void Draw_Bullet_Flash(void)
{
// Draws and animates the bullet flashes when your bullets hit something
	for (counter=0;counter<MAX_BULLETS;counter++)
		if (bulletflash[counter].state==ON)
		{
				
			if (bulletflash[counter].curr_frame)  // Don't move the first frame
			// bulletflash.xv and bulletflash.yv left out, but can easily be added
			{
				bulletflash[counter].x-=warbird.xv;
				bulletflash[counter].y-=warbird.yv;
			}

			// Draw the flash
			Draw_BOBXY(&bulletflash[counter],lpddsback,(halfwidth)+bulletflash[counter].x,(halfheight)+bulletflash[counter].y);

			// Set it so Draw_BOBXY will display the next frame
			bulletflash[counter].curr_frame++;

			// Animation doesn't repeat, so if it hits the end just get rid of it
			if (bulletflash[counter].curr_frame==BULLET_FLASH_BMP_FRAMES)
			{
				bulletflash[counter].curr_frame=0;
				bulletflash[counter].state=OFF;
			}	
				
		}
}

///////////////////////////////////////////////////////////////////

void Draw_Explode1(void)
{
// Draws and animates the small explosions used when the bombs blow up. Otherwise exactly the same as Draw_Bullet_Flash
	for (counter=0;counter<MAX_BOMBS;counter++)
		if (explode1[counter].state==ON)
		{
				
			if (explode1[counter].curr_frame)  // Don't move the first frame
			{
				explode1[counter].x-=warbird.xv;
				explode1[counter].y-=warbird.yv;
			}
				
			// Draw the explosion	
			Draw_BOBXY(&explode1[counter],lpddsback,(halfwidth)+explode1[counter].x,(halfheight)+explode1[counter].y);

			// Set it so Draw_BOBXY will display the next frame
			explode1[counter].curr_frame++;

			// Animation doesn't repeat, so if it hits the end just get rid of it
			if (explode1[counter].curr_frame==EXPLODE1_BMP_FRAMES)
			{
				explode1[counter].curr_frame=0;
			    	explode1[counter].state=OFF;
			}	
				
		}
}



	
///////////////////////////////////////////////////////////////////

void Draw_Explode2(void)
{
// Draws and animates the larger explosions used when your ship blows up. Otherwise exactly the same as Draw_Bullet_Flash
	for (counter=0;counter<MAX_EXPLODE2;counter++)
		if (explode2[counter].state==ON)
		{
			if (explode2[counter].curr_frame)  // Don't move the first frame
			{
				explode2[counter].x+=explode2[counter].xv-warbird.xv;
				explode2[counter].y+=explode2[counter].yv-warbird.yv;
			}

			// Draw the explosion
			Draw_BOBXY(&explode2[counter],lpddsback,(halfwidth)+explode2[counter].x,(halfheight)+explode2[counter].y);

			// Set it so Draw_BOBXY will display the next frame
			explode2[counter].curr_frame++;

			// Animation doesn't repeat, so if it hits the end just get rid of it
			if (explode2[counter].curr_frame==EXPLODE2_BMP_FRAMES)
			{
				explode2[counter].curr_frame=0;
				explode2[counter].state=OFF;
			}	
				
		}
}

///////////////////////////////////////////////////////////////////

void Draw_Damage(void)
{
// Draws and animates the puffs of flame used when the small rocks blow up.
	for (counter=0;counter<MAX_SMALL_ROCKS;counter++)
		if (damage[counter].state==ON)
		{
			// damage is just the name of the graphical object.
			damage[counter].x+=damage[counter].xv-warbird.xv;
			damage[counter].y+=damage[counter].yv-warbird.yv;

			// Draw the puff of flame
			Draw_BOBXY(&damage[counter],lpddsback,(halfwidth)+damage[counter].x,(halfheight)+damage[counter].y);

			// Set it so Draw_BOBXY will display the next frame
			damage[counter].curr_frame++;

			// Animation doesn't repeat, so if it hits the end just get rid of it
			if (damage[counter].curr_frame==DAMAGE_BMP_FRAMES)
			{
				damage[counter].curr_frame=0;
			    	damage[counter].state=OFF;
			}	
				
		}
}

///////////////////////////////////////////////////////////////////////

void Create_Medium_Rock(float x, float y)
{
// Assumes rocks are compacted in array
	
	// Don't make another rock if the array is full
	if (numberofmediumrocks==MAX_MEDIUM_ROCKS) return;
	
 	// Randomly set attributes

	Set_Anim_Speed_BOB(&mediumrocks[numberofmediumrocks],2+rand()%4);
   	Set_Vel_BOB(&mediumrocks[numberofmediumrocks], (-MEDIUM_ROCK_BASE_SPEED) + ( rand() % (MEDIUM_ROCK_BASE_SPEED*2+1) ), (-MEDIUM_ROCK_BASE_SPEED) + ( rand() % (MEDIUM_ROCK_BASE_SPEED*2+1) ));
   	
   	// hp of rock - half the range + a random percent of the range
   	rockhp.medium[numberofmediumrocks]=MEDIUM_ROCK_HP - (ROCK_HP_RANGE/2 * MEDIUM_ROCK_HP) + (rand() % (int)(ROCK_HP_RANGE * MEDIUM_ROCK_HP));

   	Set_Pos_BOB(&mediumrocks[numberofmediumrocks], x,y);
   	// mediumrocks[numberofmediumrocks].state = ON;
   	
   	numberofmediumrocks++;

}

////////////////////////////////////////////////////////////////////////

void Create_Small_Rock(float x, float y)
{
// Assumes rocks are compacted in array

	// Don't make another rock if the array is full
	if (numberofsmallrocks==MAX_SMALL_ROCKS) return;
	
 	// Randomly set attributes

	Set_Anim_Speed_BOB(&smallrocks[numberofsmallrocks],2+rand()%3);
   	Set_Vel_BOB(&smallrocks[numberofsmallrocks], (-SMALL_ROCK_BASE_SPEED) + ( rand() % (SMALL_ROCK_BASE_SPEED*2+1) ), (-SMALL_ROCK_BASE_SPEED) + ( rand() % (SMALL_ROCK_BASE_SPEED*2+1) ));
   	
   	// hp of rock - half the range + a random percent of the range
   	rockhp.small[numberofsmallrocks]=SMALL_ROCK_HP - (ROCK_HP_RANGE/2 * SMALL_ROCK_HP) + (rand() % (int)(ROCK_HP_RANGE * SMALL_ROCK_HP));

   	Set_Pos_BOB(&smallrocks[numberofsmallrocks], x,y);
   	// smallrocks[numberofsmallrocks].state = ON;
   	
   	numberofsmallrocks++;

}

/////////////////////////////////////////////////////////////////////////

void Draw_Warp(void)
{
// Draws a flash in the center of the screen.

	Draw_BOBXY(&warp,lpddsback,halfwidth,halfheight);

	// Set it so Draw_BOBXY will display the next frame
	warp.curr_frame++;

	// Animation doesn't repeat, so if it hits the end just get rid of it
	if (warp.curr_frame==WARP_BMP_FRAMES)
	{
		warp.curr_frame=0;
		warp.state=OFF;
	}
}

/////////////////////////////////////////////////////////////////////

void Damage_Player(int dmg)
{
	// Take dmg energy from the player's store of energy
	energy-=dmg;
	
	// Check to see if this killed the player
	if (energy<0)
	{	
		// Player is killed, so setup the explosion object to start animating in the center of the screen
	    	explode2[Explode2QueueCounter].state=ON;
	    	explode2[Explode2QueueCounter].y=0.0;
    		explode2[Explode2QueueCounter].x=0.0;
    		explode2[Explode2QueueCounter].xv=warbird.xv;
    		explode2[Explode2QueueCounter].yv=warbird.yv;
    	
    		// Update the array index to the next available slot.  While it's unlikely you'll have the death explosion animating more than once at a time, this is for future additions
    		Explode2QueueCounter++;
  	  	if ((Explode2QueueCounter)==(EXPLODE2_BMP_FRAMES)) Explode2QueueCounter=0;
  	  	
  	  	// Set the flag used to tell the main loop the player is dead
  	  	playerdead=ON;
  	  	
  	  	// Setup next ship for when you respawn
  	  	
  	  	warbird.xv=0.0; warbird.yv=0.0; warbird.curr_frame=0; energy=MAX_ENERGY;
		bullettimer=bombtimer=0; numberofbullets=0; numberofbombs=0; lives--;
		warp.state=OFF;
		
		// Turn off thruster sound loop
		if (thrustsoundplaying) {Stop_Sound(rev_id); thrustsoundplaying=OFF;}
		
		// Play Player blowing up sound
		
	    	Play_Sound(explode2_id);
	    	
	    	// Set numbers to display in center for the high score if this is the end of the game
	    	if (lives==-1)
	    	for (counter=0;counter<10;counter++)
	    		numbers[counter].y=halfheight-NUMBERS_HIGHSCORE_HEIGHT_FROM_CENTER;
	}
}


///////////////////////////////////////////////////////////////////////

void Draw_Score(void)
{
	int displayx;  // x coordinate of graphical number used to display energy
	
	// Lock the back surface for writing
	DD_Lock_Back_Surface();
	
	// start the first number 40 pixels from the right edge of the screen
	displayx=width-20;
	
	// Put the player's score into a character buffer for display
	ltoa(score,buffer,10);
	
	for (counter=0;buffer[counter];counter++); // set counter to end of string
	// Counter now points at the end of the string
	
	counter--;  // move away from null terminator
	
	// Use numbers[offset] to display offset graphical number
	while (counter>=0)
	{
		// Subtract 48 from the character to get the real number.  Note the index of the graphic array is also the graphic number image in that element.  For example,
		// numbers[5] holds the graphical image of a 5
		numbers[buffer[counter]-48].x=displayx;
		
		// Draw the number
		Draw_Bitmap(&numbers[buffer[counter]-48],back_buffer,back_lpitch,1);
		
		// The last number in the buffer is displayed first, then one from the last, etc
		counter--;
		
		// Move over 20 pixels to draw the next number
		displayx-=20;
	}

	// Unlock the back surface	
	DD_Unlock_Back_Surface();
}

///////////////////////////////////////////////////////////////

void About(void)
{
	
	BITMAP_IMAGE about;
	
	// Load the 8 bit color bitmap
	if (!Load_Bitmap_File(&bitmap8bit, "about.bmp")) error("Function Load_Bitmap_File Failure when loading about.bmp");

   	// Create a Bitmap the size of the about.bmp file.  Note the image isn't loaded yet.  counter is just used to hold the error code
   	counter=Create_Bitmap(&about,GetSystemMetrics(SM_CXSCREEN)/2 - bitmap8bit.bitmapinfoheader.biWidth / 2,GetSystemMetrics(SM_CYSCREEN) / 2 - bitmap8bit.bitmapinfoheader.biHeight / 2,bitmap8bit.bitmapinfoheader.biWidth,bitmap8bit.bitmapinfoheader.biHeight);
   	if (!counter)   {  error("Function Create_BitMap Failure");      }
   	
	// Load the data from bitmap8bit into about
   	Load_Image_Bitmap(&about, &bitmap8bit, 0,0,1);


	// clear the drawing surface
	DD_Fill_Surface(lpddsprimary, 0);
	
	// Sit around so the user can read the instructions.
	 while (!quit)
	 {
	 	
	 	// Refresh the About graphic
		DD_Wait_For_Vsync();
		DD_Lock_Primary_Surface();
		Draw_Bitmap(&about,primary_buffer, primary_lpitch, 0);
		DD_Unlock_Primary_Surface();
 	
	 	// Read from the keyboard
		DI_Read_Keyboard();
		
		// Quit the game if the user hits escape
		if (keyboard_state[DIK_ESCAPE]) {quit=ON;}
		
		// Continue if the user hits the spacebar
		else if (keyboard_state[DIK_SPACE]) break;

	}
	
	// delete the about bitmap since it will probably only be used once
	Unload_Bitmap_File(&bitmap8bit);
	
	// Destroy the about object
	Destroy_Bitmap(&about);
	
	// Draw the title back to the primary surface so the user can see the commands to start the game
	DD_Lock_Primary_Surface();
	Draw_Bitmap(&title,primary_buffer, primary_lpitch, 0);
	DD_Unlock_Primary_Surface();
}

//////////////////////////////////////////////////////////////////////////////

void Title(void)
{
	

	// Lock the back surface
	DD_Lock_Back_Surface();

	// Write bitmap to the back surface
	Draw_Bitmap(&title,back_buffer,back_lpitch,1);

   	// Unlock the surface
	DD_Unlock_Back_Surface();

	
}

/////////////////////////////////////////////////////////////////////

void Dead(void)
{

	int displayx;  // x coordinate of graphical number used to display energy
	long highestscore=0L;
	int highestscoredifficulty;
	int counter2;
	
	// Determine the overall high score from all difficulty levels
	// Assume to start with the highest score is the score you just got
	highestscore=score;
	// Assume the difficulty level played when the player got the highest score is the current one
	highestscoredifficulty=skilllevel;
	
	// Determine the actual highest score
	for (counter=0;counter<4;counter++)
	{
		if (highscore[counter]>highestscore) {highestscore=highscore[counter]; highestscoredifficulty=counter;}
	}
	
	// Convert the highest score into a string stored in the buffer array
	ltoa(highestscore,buffer,10);
	
	// Displayx is the leftmost position of the highscore number.  9 is .5 * (16 + 2) where 16 is half the width of a number graphic and 2 is a pad between numbers
	displayx=halfwidth-9*strlen(buffer);
	
	// Lock the back surface for writing 
  	DD_Lock_Back_Surface();
  	
  	// This loop draws the highest score in the center of the screen
	for (counter2=0;buffer[counter2]!=0;counter2++)
	{
		// Set the x cordinate of the number you will display.  The y coordinate was already set when you died.
		numbers[buffer[counter2]-48].x=displayx;
		
		// Draw the appropriate number graphic for whatever character you are displaying from the buffer
		Draw_Bitmap(&numbers[buffer[counter2]-48],back_buffer,back_lpitch,1);;
		
		// Draw the next number 20 pixels to the right
		displayx+=20;
	}
	
	// Draw the bitmap containing the graphic for whatever difficuly level you got that high score from
	if (highestscoredifficulty==0) Draw_Bitmap(&lamer_graphic,back_buffer,back_lpitch,1);
	else if (highestscoredifficulty==1) Draw_Bitmap(&dueler_graphic,back_buffer,back_lpitch,1);
	else if (highestscoredifficulty==2) Draw_Bitmap(&hunter_graphic,back_buffer,back_lpitch,1);
	else Draw_Bitmap(&rakkar_graphic,back_buffer,back_lpitch,1);
	
  	// Draw the dead.bmp graphic over the screen
	Draw_Bitmap(&dead,back_buffer,back_lpitch,1);

	// Unlock the surface
	DD_Unlock_Back_Surface();
	

	// Note I didn't flip the secondary surface over.  This is because the rocks and such are still animating in the background so flipping occurs in the main loop after the other
	// graphics are drawn
}


//////////////////////////////////////////////////////////////////////////////

void Draw_Lives(void)
{
	int yellowshields,greenballs;
	int displayx;  // x coordinate of graphical number used to display energy
	
	// Yellow shields represent SHIELD_LIVES each.
	yellowshields=lives/SHIELD_LIVES;
	
	// Green balls represent 1 life each
	greenballs=lives-yellowshields*SHIELD_LIVES;
	
	// Start drawing 16 pixels from the rigth of the screen
	displayx=width-16;

	// Draw the yellow shields
	for (counter=0;counter<yellowshields;counter++)
	{
	    	Draw_BOBXY(&shield1,lpddsback,displayx,SHIELDY);
	    	displayx-=16;
	}
	
	// Draw the green balls.  The variable display x is passed over from the previous for loop in case any yellow shields were drawn
	for (counter=0;counter<greenballs;counter++)
	{
		Draw_BOBXY(&shield2,lpddsback,displayx,SHIELDY);
	    	displayx-=16;
	}
		
	if (lives)
	{
		// Update the animations so the shields and balls rotate
		Animate_BOB(&shield1);
		Animate_BOB(&shield2);
	}
}

//////////////////////////////////////////////////////////////////////

int Load_Highscores_From_File(char *filename)
{
	int counter2,counter3;
	char buffer2[20];
	HFILE fp_file;
	unsigned int length;

	if (!(fp_file=_lopen(filename,OF_READ)))
	{
		// Can't open or find file.  Just set all highscores to 0 and exit
     		highscore[0]=0L;
		highscore[1]=0L;
		highscore[2]=0L;
		highscore[3]=0L;
		return(0);
     	}
     	
	length=_lread(fp_file,buffer,80);
	
	// counter3 is used to index the main buffer where the data from the _lread operation is held
	counter3=0;
      	
      	// counter 2 loops through each of the 4 high score elements in the highscore array
      	for (counter2=0;counter2<4;counter2++)
	{
		// counter cycles through single number buffer, buffer 2
		counter=0;
		while(counter3<length)
		{

			// Copy part of score from buffer into buffer2
			buffer2[counter++]=buffer[counter3++];
			if (counter==20)  // Bad input
			{
			   	highscore[0]=0L;
				highscore[1]=0L;
				highscore[2]=0L;
				highscore[3]=0L;
				return(0);
			}
			if (buffer[counter3]==EOF) break;
			if (buffer[counter3]=='\r')
			{
				counter3+=2;  // skip the '\n' character
				break; // End of number, break and write it into the highscore array
			}
  					
   		}
   		
     		buffer2[counter]=0; // Add the null byte to the string held in buffer2
     		
		highscore[counter2]=atol(buffer2);  // Convert the high score to a long and save it in the highscore array
     	}

// return success
return(1);
}

///////////////////////////////////////////////////////////   
   
int Save_Highscores_To_File(char *filename)
{

FILE *fp_file; // working file

// try and open file
if ((fp_file = fopen(filename,"wt"))==NULL)
   return(0);
char buffer2[20];

ltoa(highscore[0],buffer2,10);

// High scores are written with characters because I couldn't get fprintf to work.
strcpy(buffer,buffer2);
strcat(buffer,"\n");
ltoa(highscore[1],buffer2,10);
strcat(buffer,buffer2);
strcat(buffer,"\n");
ltoa(highscore[2],buffer2,10);
strcat(buffer,buffer2);
strcat(buffer,"\n");
ltoa(highscore[3],buffer2,10);
strcat(buffer,buffer2);
strcat(buffer,"\n");

    // read the next entry in
    fprintf(fp_file,buffer);

// close the file
fclose(fp_file);

// return success
return(1);

}

///////////////////////////////////////////////////////////
